<MenuItem x:Name="newProjectButton" Click="OnNewProjectButton_Click" Header="_New Project">
</MenuItem>
I want to call OnNewProjectButton_Click whenever Alt+N is pressed. The code above doesn't work, unfortunately, because the handler is called only if the menu is expanded (i.e. has focus).
You could use ApplicationCommands.New for this since it already provides that functionality. The default WPF Command Model is pretty cool. Even if you decide not to use the default commanding model, that second link should show you how to hook up the input gestures you need.
EDIT: Here is a sample implementation...
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.New"
CanExecute="NewApplicationCommand_CanExecute"
Executed="NewApplicationCommand_Executed" />
</Window.CommandBindings>
<Grid>
<Menu>
<MenuItem Header="_File">
<MenuItem Command="ApplicationCommands.New" Header="_New Project" />
</MenuItem>
</Menu>
</Grid>
And the code behind...
private void NewApplicationCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
// Whatever logic you use to determine whether or not your
// command is enabled. I'm setting it to true for now so
// the command will always be enabled.
e.CanExecute = true;
}
private void NewApplicationCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
Console.WriteLine("New command executed");
}
You see to set the InputGestureText on the menu item
<MenuItem Header="Paste"
ToolTip="Paste the selected text to text box"
InputGestureText="Ctrl+V" />
But unlike WinForms the "The application must handle the user's input to carry out the action".
So consider using the WPF commands as they do this for you automatically. I found that Windows Presentation Foundation Unleashed covers this well.
Related
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;
}
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>
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
I have a simple menu in a WPF Client C# application where the user should be able to select only one item at a time. If one of the items is selected, the other items should be disabled until the operation is completed.
For example, I have the following menu
<MenuItem Header="Help">
<Separator></Separator>
<MenuItem Header="User Manual.." Click="UsageDocMenuItem_Click" />
<Separator></Separator>
<MenuItem Header="Login" Click="LoginItem_Click"/>
<Separator></Separator>
<MenuItem Header="About" Click="AboutMenuItem_Click"/>
<Separator></Separator>
</MenuItem>`
If user clicks Login, User manual and About should be disabled until the operation trigerred by Login is finished.
Which C# design or code method can be used to implement this?
So means there are menu items and when User clicks on one of them for example : Login
Then till the time action is completed Login should be enabled and other menu items should be disabled.
You need to create an event of button click and within the same you need to write the code to find the other menu items and disable them.
Button_click Event(...)
{
//...disable other menu items
}
Assuming you are using 'WPF', you can use commands and your ViewModel that contains these commands to determine whether the command is enabled or not. This way it is also your ViewModel that knows the 'mode' you are in.
I found the solution. I am not sure if we can use IDs of selected menu item since I want to disable the whole menu at once. I can so something like this:
<MenuItem Header="Help" Name="help">
<Separator></Separator>
<MenuItem Header="User Manual.." Click="UsageDocMenuItem_Click" />
<Separator></Separator>
<MenuItem Header="Login" Click="LoginItem_Click"/>
<Separator></Separator>
<MenuItem Header="About" Click="AboutMenuItem_Click"/>
<Separator></Separator>
</MenuItem>`
void UsageDocMenuItem_Click()
{
help.IsEnabled = false;
//Do stuff
help.IsEnabled = true;
}
By giving a name to the menu item, I can access it anywhere in the code.
Your question is not very detailed. If all you need is the basic logic/concept, then perhaps all you need is a method like this?:
public void DisableAllButOneMenuItem(int idOfSelectedMenuItem)
{
// Code that disables all itmes,
// then code that enables a single item again.
}
I would like to control when the contextmenu of my control to show or not.
here is my code:
void MyControl_MouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if ( some condition .....)
{
this.Focus();
contextmeun.PlacementTarget = this;
contextmeun.IsOpen = true;
}
}
However, it just show up less than 1 second then disappear immediately. Why is that?
Thank you for all your help!
Probably because you're focussing the control that the context menu belongs to, then showing the context menu, however when the parent control gets focus, the context menu closes.
Try setting the context menu in Xaml instead to get the correct behaviour
<MyControl>
<MyControl.ContextMenu>
<ContextMenu>
<!-- Define context menu here -->
</ContextMenu>
</MyControl.ContextMenu>
</MyControl>
This can be done in pure XAML form, all you need to do is bind your visibility of context menu with a bool property containing your condition like this -
<YourControl>
<YourControl.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</YourControl.Resources>
<YourControl.ContextMenu>
<ContextMenu Visibility="{Binding IsEnable,
Converter={StaticResource BooleanToVisibilityConverter}}">
<MenuItem Header="MenuItem1"/>
<MenuItem Header="MenuItem2"/>
<MenuItem Header="MenuItem3"/>
</ContextMenu>
</YourControl.ContextMenu>
</YourControl>
Here IsEnable is a plain CLR property, in its getter you can have the logic for your condition depending on which you need to toggle the visibility of your context menu..