Having multiple Controls using the same CommandBinding in WPF? - c#

In my Window, there are several controls which perform the same action.
For example I have a MenuItem
<MenuItem x:Name="_mnuNew" Command="New" Header="_New" InputGestureText="Ctrl+N"/>
and a Button
<Button x:Name="_btnNew" Command="New"/>
performing the "New" Command
<Window.CommandBindings>
<CommandBinding Command="New" CanExecute="IsNewExecuteable" Executed="NewExecute" />
</Window.CommandBindings>
The assignment works as desired for the MenuItem. Setting the Command for the Button results in a NullReferenceException
I've read here that Command Bindings do also work on Buttons, so what am I doing wrong.
EDIT:
private void IsNewExecuteable(object sender, System.Windows.Input.CanExecuteRoutedEventArgs e)
{
e.CanExecute = IsRunning; //IsRunning is a siple property that is tested and works
}

The whole CommandBinding Part was fine but there was a mistake inside of IsNewExecuteable, in which I trusted and which was obviously wrong.
Excuse me for Posting this question, everytime I am using a technique new to me I don't see obvious misstakes.
Anyway thanks a lot to those who helped

Related

DataGrid ContextMenu MenuItems are sometimes disabled

I have a DataGrid and I do not know, why the MenuItems of ContextMenu are sometimes enabled and sometimes disabled.
<DataGrid ItemsSource="{Binding Values}">
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Command="Copy" />
<MenuItem Command="Paste" />
<MenuItem Command="Delete" />
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
What can be the cause for that? I did not find any code, which is responsible for setting the ICommand.CanExecute or the MenuItem.IsEnabled.
Please tell me which information I still need to provide.
#Maverik: I do not wrote any code for those three standard .NET commands:
ApplicationCommands.Delete
ApplicationCommands.Copy
ApplicationCommands.Paste
Your MenuItems are built-in WPF commands. Accordingly to MSDN documentation their implementation depends on control where commands were triggered and in your case from the state of DataGrid(row selected or not etc.).
...The implementation logic is bound to the command with a
CommandBinding. For example, if the Close command is executed on a
control, the logic which performs the Close command may not be
provided by the control, so the application writer will be responsible
for writing the logic that determines how the control will handle the
command.
Many controls do provide implementation logic for many of the commands
in the command library. For example, the TextBox class provides logic
for the Paste, Cut, Copy, Undo, and Redo commands.
See ApplicationCommands Class.
You can impact your ContextMenu by putting in XAML:
<DataGrid.CommandBindings>
<CommandBinding Command="Copy" CanExecute="CommandBinding_CanExecute"/>
</DataGrid.CommandBindings>
and in code behind:
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = false;//put here your logic
e.Handled = true;
}

Is using command binding or event handler a better approach to implement Close, Minimize and Maximize Buttons in WPF?

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.

How to track WPF commands?

In a WPF application, I want to have a User Tracking System to keep statistics on the way users are using the application. In other words, I'm looking for a way to track what commands are being executed and how they have been triggered by the user (by clicking on the toolbar button, by using keyboard shortcuts, etc). So far, I haven't found a nice way to do this while using the WPF command pattern...
Do you have ideas/suggestions on how to achieve/design something like this without overriding every control used in the application?
For discussion purposes, I created a very basic WPF application containing a toolbar with a single Save button, a TextBox and a ListBox. I also added a KeyBinding to trigger the Save command when pressing CTRL+S.
The first challenge is to determine which device (mouse or keyboard) was used to trigger the command.
The second challenge is to determine what is the control used to trigger the command (the command source). I'm not interested to know which control had keyboard focus when the command was triggered, I would like to know what control was used to trigger the command (usually it's a button, an hyperlink, a MenuItem from a ContextMenu, etc.)
MainWindow.xaml
<Window x:Class="TrackingCommands.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" x:Name="Me" Height="480" Width="600">
<Window.CommandBindings>
<CommandBinding Command="Save" Executed="OnSaveCommandExecuted" CanExecute="OnSaveCommandCanExecute" />
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Command="Save" Gesture="CTRL+S"/>
</Window.InputBindings>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<ToolBarTray Grid.Row="0">
<ToolBar>
<Button Command="Save" Content="Save"/>
</ToolBar>
</ToolBarTray>
<TextBox Grid.Row="1" TextWrapping="Wrap" AcceptsReturn="True"/>
</Grid>
</Window>
MainWindow.xaml.cs
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private void OnSaveCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
e.Handled = true;
}
private void OnSaveCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
e.Handled = true;
}
}
EDIT
I realized my original question was a bit vague, I apologize. I will try to give more information and ask a more precise question.
I know it is simple enough to store a list of commands that have been executed. The challenge here is to retrieve which device was used to trigger the command initially: mouse or keyboard?
By putting the tracking logic in the "executed" handler, there is no way at this point to determine if the user triggered the command by clicking a button with the mouse, by pressing Enter on the button or if he used a keyboard shortcut. In my example, the same command can be triggered by clicking the toolbar button or by pressing CTRL+S on keyboard. How can I track these separate actions that will all trigger the same command?
Can this be achieve in the ViewModel layer? When we reach the command handler, it's already too late: we have lost this information. The only place we really know the device used is in the View itself. How to pass this information to the Command handler? Is the only way to do this is to override the Button control to intercept Click and KeyDown events in order to provide additional context to the command handler?
If you use the MVVM pattern then the Command would be bound from the View to a Command instance in the View Model. You could use create an ICommand implementation that provided an event when it was executed with some details about itself. Maybe use a command provider/factory/whatever to create each command and wire it up to a logger/tracker.
Create a Singleton or static class that has a Stack<ICommand> property and pass a reference to this class to your Windows (or preferably view models). You should of course encapsulate the Stack object using some typical AddCommand and RemoveCommand methods. Then, whenever an ICommand is called, Push it into the Stack.
However, you'll either need to define your ICommands in separate classes, or preferably use a form of the RelayCommand found online. Here's an example:
private ActionCommand deleteCommand = new ActionCommand(action => DeleteCommand(AudioTrack),
canExecute => CanDelete(AudioTrack));
public override ICommand Delete
{
get { return deleteCommand; }
}
private void DeleteCommand(AudioTrack audioTrack)
{
// Do work then add to Stack in CommandManager
CommandManager.AddCommand(deleteCommand);
}
private bool CanDelete(AudioTrack audioTrack)
{
return audioTrack != null;
}
I'm not exactly sure what your second question means, because the ICommands are set as the value to the Command property of the relevant control, so you should already know what controls they are, eg.:
<MenuItem Header="Delete track" Command="{Binding Delete}"
CommandParameter="{Binding Release.ThinDiscs.CurrentItem}">
<MenuItem.Icon>
<Image Source="pack://application:,,,/App;component/Images/Delete.png" />
</MenuItem.Icon>
</MenuItem>

WPF Buttons not instantiating

I'm having the weirdest problem and it's driving me insane.
I've created a WPF MVVM program and everything was working alright, however, now when I open the program and click on a button, I receive a System.NullReferenceException. I put a breakpoint where the error occurs and the button isn't instantiated, however, the form shows just fine and the buttons are clickable. In fact, none of the buttons instantiate (every button on my form gives the same error, and when I set a breakpoint after InitializeComponent(), none of the buttons show up under this - all the other components show up.
Here is sample code for the button:
MainWindow.xaml
<Button Content="A"
Command="{Binding KeyButtonClickCommand}"
Style="{StaticResource keyButtonStyle}" />
The method throwing an error is in my ViewModel, the button is bound to a command:
private void keyButton_Click(object sender)
{
Button btn = (Button)sender;
string tempKey = "";
tempKey = btn.Content.ToString();
this.Key = tempKey;
}
Breakpoint after InitializeComponent()
Breakpoint after error
Like I said, was working just fine earlier, now just went on the fritz.
What worries me most is that maybe I've done something that I shouldn't have and it might affect future projects. I'd just like to double-check whether it's that, or just a freak occurrence.
Thanks.
If I am understanding your question correctly you are getting the argument for your keyButton_Click method as null.
This is most likely because you are not passing in a CommandParameter to your command. If you want to pass the button itself into the command, try the following XAML.
<Button Content="A"
Command="{Binding KeyButtonClickCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}}"
Style="{StaticResource keyButtonStyle}" />
I do want to note the whole point of MVVM is to not interact with the actual UI layer directly in your ViewModel and when you pass your button to your ViewModel like this you are doing exactly that.
Edit : As noted in the comments if you want to pass "A" as argument to your command you should just set that as your CommandParameter.
<Button Content="A"
Command="{Binding KeyButtonClickCommand}"
CommandParameter="A"
Style="{StaticResource keyButtonStyle}" />

KeyBinding not working when switching Windows

My MainWindow has some KeyBindings:
<Window.InputBindings>
<KeyBinding Command="{Binding NewFileCommand}" Key="{Binding NewFileCommand.Key}" Modifiers="{Binding NewFileCommand.Modifiers}" />
</Window.InputBindings>
They´re working, as long as i clicked somewhere into the content of my Window. But if I use Alt+Tab to switch between Applications (let´s say MS Word and my App) the Shortcuts won´t work anymore until I click again somewhere into the View. Same when selecting the Application-Window via Mouse on the Border.
How can I make them working?
In my repro, I used the RelayCommand from MVVM Light which worked fine. I'm guessing that you are using something else. Try adding this code in your window:
private void Window_Activated(object sender, EventArgs e)
{
System.Windows.Input.CommandManager.InvalidateRequerySuggested();
}
That tells the command framework that something has changed and it should re-evaluate the CanExecute status of each command.

Categories