Very new to XAML/C# and I wanted to know how to send a parameter from XAML to a C# method.
This TextBlock <TextBlock PreviewMouseDown="changeFont" /> would call a method with the signature
changeFont(object sender, MouseButtonEventArgs e)
But I wanted to know if I could add a parameter to the signature like this:
changeFont(object sender, MouseButtonEventArgs e, string Name)
and send an argument via XAML
<TextBlock PreviewMouseDown="changeFont('Bob')" />
There is no way to do this in WPF; that's not how it's designed. If you need additional information to process the PreviewMouseDown event, you'll have to get it from somewhere else.
sender gives you the element that raised the event (in your case the TextBlock). So one option is to use the Tag property:
<TextBlock PreviewMouseDown="changeFont" Tag="Bob"/>
changeFont(object sender, MouseButtonEventArgs e)
{
var moreInfo = ((TextBlock)sender).Tag;
...
}
One other thing to look into is the use of commands. Commands let you add a CommandParameter. Certain controls Command property that can be set to execute said command when they are interacted with, like when a Button is clicked. This isn't the case for TextBlock, but it might be useful later on.
No, this is not possible. The XAML snippet PreviewMouseDown="changeFont" attaches an event handler to the PreviewMouseDown event. And the event handler changeFont needs to have a fixed signature. You cannot simply add a parameter.
That being said, changeFont does not sound like the name of an event handler anyway. It is an action. If you have multiple of these text blocks and you want to re-use the changeFont method, you could define separate event handlers that each call the action:
<TextBlock PreviewMouseDown="BobPreviewMouseDown" />
<TextBlock PreviewMouseDown="AlicePreviewMouseDown" />
void BobPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
changeFont("Bob");
}
void AlicePreviewMouseDown(object sender, MouseButtonEventArgs e)
{
changeFont("Alice")
}
That's one option. Of course, there are many others. You could, e.g., also have a single event handler and derive the parameter from the sender object (e.g. with an attached property or similar).
You should use Command and CommandParameter properties. It's better to use MVVM pattern and link to a command from your ViewModel, but if you don't use it, you also can use the Routed Command system and set an event handler for the command via CommandBinding property:
<Button Content="Bob button"
Command="{Binding ChangeFont}"
CommandParameter="Bob" />
I used <Button /> here, but if you want it to look like a <TextBlock /> you can change its appearance by changing it's Template property. But remember, that user expects that a button behaves like a button while a text block behaves like a text block.
Related
Imagine you have a WPF project with a main window like this:
<StackPanel>
<TextBox Name="TextBox1" Text="Test" TextChanged="TextBox1_TextChanged" />
<TextBox Name="TextBox2" />
</StackPanel>
and codebehind like this:
private void TextBox1_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox2.Text = TextBox1.Text;
}
When you run it you get a NullReferenceException, because TextBox2 does not exist at the time that TextBox1 is initialized and its Text set, which raises the event. To avoid this, I can either subscribe to the event in the window's constructor, after InitializeComponent(), instead of in XAML, or add a check for IsLoaded at the top of the event handler. Both of these seem a little hacky.
Wouldn't it be better if the auto-generated code from the XAML initialized all controls but waited to subscribe to events until the end? In most cases I can't imagine you'd actually want to raise an event in the constructor anyway. Am I missing a reason why this would be a bad idea? I realize this might break existing code, but it could be an optional feature that only starts out enabled for new projects.
I'm currently learning to code WPF application after having used forms for a while.
I have a simple question, but can't seem to find an anwser anywhere.
Is it possible to automatically generate the 'private void eventName(...' code when creating an event ?
For example, if I create a WPF Form with a simple button and code :
Button x:Name = "mButton" Content = "Hello" Click = "mClick" /
Is there a trick to have the private void event handler create itself ? Cause right now, I either write it manually or double click in the event handler properties tab. In widowsForm, I could just double click and it would create itself.
This isn't a big issue for 1 or 2 but if I want to create a dozen buttons, it can become tedious.
I apologize if the question can seem obvious
Of-course, the more automated and lazier the better.
So a few tips:
You can generate a new event handler with an automated name like this:
Assign the x:Name before creating or assigning the event handler
Pick the default <New Event Handler> from the list of options IDE gives you for your event handler. it will generate something like:
MouseDoubleClick="mButton_MouseDoubleClick"
or Click="mButton_Click"
If the name is already taken, it will be prefixed with _1
If the x:Name is not assigned, it will be prefixed with Button_ instead of x:Name
You can generate any already-written event handler like this:
Right click on handler's name in XAML code ("mClick") and choose Go To Definition (The default shortkey is F12)
F12 does the same thing as double-clicking on an event handler value in properties window in WinForms. In case of default event (like Button's Click, it does the same as double-clicking directly on the control)
If you don't want the control to contain any code for event handler like:
<Button /> // handles the click event magically
Then you can add this to the container of all the buttons:
<Container.Resources>
<Style TargetType="Button">
<EventSetter Event="Click" Handler="mClick"/>
</Style>
</Container.Resources>
(obviously, I supposed the name of the container is Container. In your case it might be Window or Menu etc.)
Now every button inside this container has its Click handled by the same handler, in which you can redirect your logic to the right method:
Dictionary<string, Action> dic;
private void mClick(object sender, RoutedEventArgs e)
{
dic[(sender as Button).Name]();
}
These all still so tedious compared to MVVM pattern:
<ItemsControl ItemsSource="{Binding myButtons}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding ButtonText}" Command="{Binding ButtonAction}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If you want to do this rather than use a databinding/command pattern, you can use the XAML designer in Visual Studio. If you start typing Click=" you should be prompted with a list of possible event handlers or a new one - selecting one and pressing tab will create the event handler in the code behind for you (you might want to rename it, or make sure you name the button in XAML first).
For my current project I need to capture button pressed and release events in Xamarin.Forms. But I want to keep things loosely coupled using Prism.
At first I used the Command property of the , like so:
<Button x:Name="ButtonForward" Command="{Binding MoveUpCommand}" />
But the Command property only fires when the button is released. To make seperate pressed and released actions I used the events in XAML:
<Button x:Name="ButtonForward" Pressed="ButtonForward_Pressed" Released="ButtonMove_Released"/>
And called the Commands manually in the event handlers in code behind:
private void ButtonMove_Released(object sender, System.EventArgs e)
{
var vm = BindingContext as DirectControlViewModel;
if (vm.MoveStopCommand.CanExecute(null))
vm.MoveStopCommand.Execute(null);
}
private void ButtonForward_Pressed(object sender, System.EventArgs e)
{
var vm = BindingContext as DirectControlViewModel;
if (vm.MoveUpCommand.CanExecute(null))
vm.MoveUpCommand.Execute(null);
}
The problem is that it isn't loosely coupled anymore, since the View now has to know its ViewModel.
Is there a way to have a button that does have seperate commands for pressed and released events, keeping the View and ViewModel loosely coupled? Any help would be appreciated.
Use the EventToCommandBehavior on the Button. This will allow you take advantage of any Event on anything you're working with and Execute a Command when the event is fired.
<Button>
<Button.Behaviors>
<prism:EventToCommandBehavior EventName="Pressed"
Command="{Binding PressedCommand}" />
<prism:EventToCommandBehavior EventName="Released"
Command="{Binding ReleasedCommand}" />
</Button.Behaviors>
</Button>
Note there are additional properties that you can utilize if you have some sort of Parameter that you would like to pass the Command which may be a property in the EventArgs, or something else entirely that you'd like to bind to or specify.
I am making the close, maximize and minimize buttons in WPF C#. I tried two different methods and both seemed to work with me but I just want to know which approach in general is considered a better practice for this kind of implementation.
Method one:
in XAML:
<Window.CommandBindings>
<CommandBinding Command="{x:Static SystemCommands.CloseWindowCommand}" CanExecute="CommandBinding_CanExecute_1" Executed="CommandBinding_Executed_1" />
<CommandBinding ... />
<CommandBinding ... />
</Window.CommandBindings>
<Button Command="{x:Static SystemCommands.CloseWindowCommand}" Content ="close"/>
<Button ... />
<Button .../>
in C#:
private void CommandBinding_Executed_1(object sender, ExecutedRoutedEventArgs e)
{
SystemCommands.CloseWindow(this);
}
...
Method two:
in XAML:
<Button Content="X" Click="CloseButton_Click" />
<Button .../>
<Button ... />
in C#:
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
Close();
}
...
Since the close, maximize and minimize buttons are typically part of a control, or a template of a control, you could handle the Click event of the buttons directly. There is no need nor reason to introduce any command bindings just to be able to handle the click of a Button internally in a control.
You could either hook up the event handlers in XAML or, if the buttons are defined in a ControlTemplate of a custom control, you could override the OnApplyTemplate() method of the control and hook up the event handlers programmatically as suggested here: https://blog.magnusmontin.net/2013/03/16/how-to-create-a-custom-window-in-wpf/.
Button click handler is simple and fast (to implement). If you are sure you are going to use just this button to close your window - click handler is good enough. If however there is possibility you are going to need more than one place to close the window (for example - you are going to use "close" menu option) - then it's better to not spread the same logic over multiple places and use a command, because command has all handling logic in one place (CommandBinding_Executed_1 in your case). Also, command has CanExecute logic so you will be able to automatically disable your close button (and all other "close" controls) in case window cannot be closed right now (with click handler you will have to code this logic yourself). Also, with command you can close your window from any control down the tree, even if that control has no reference to your window at all. This applies to "command vs click handler" in general, not specifically to the case with closing window where some of the above might seem a bit contrieved.
I would like help regarding how to handle events from controls in a ResourceDictionary (e.g. Styles.xaml) without using ResourceDictionary Code-Behind (e.g. Styles.xaml.cs), mainly because I want the Styles.xaml to just be there for styling.
My scenario is, I have a Custom Page which uses a ResourceDictionary for DataTemplate styles (I am using a TemplateSelector). However, the problem I am currently having is for handling events. For example:
I have this in my Styles.xaml:
.
.
<Button Click="Button_Click"/>
.
And I declare this in the CustomPage.xaml.cs :
private void Button_Click(object sender, RoutedEventArgs e)
{
// some code
}
However, it does not work. Is there any way to explicitly tell that I want to use that particular Event Handler for the button's click event? Additionally, is it possible to have different handlers for each page e.g.
CustomPage2.xaml.cs:
private void Button_Click(object sender, RoutedEventArgs e)
{
// some different code from CustomPage.xaml.cs
}
Thank you!
The answer is simple: do not handle events such a way. Use bindings instead (especially, if you're using data templates). E.g., for Button:
<Button Command="{Binding MyCommand}">
where MyCommand is a ICommand-implemented instance from your data context.
If you're not familiar with data bindings in WPF, start read from here.