DataGrid ContextMenu MenuItems are sometimes disabled - c#

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;
}

Related

context menu for listview does not fire the RightTapped event

I have been working with c# for some time now but surprisingly I have never dealt with context menus before. I have a listView control in my universal windows 8.1 app. Now I am trying to get a context menu to popup for each item in the listView (they are all the same type of object and are added to the list as the user adds entries). I have run into several problems with this and have looked at code examples and they seem to be leading in different directions. Firstly when I right click on an item in the list it does not fire the ListView_RightTapped event.
<ListView x:Name="lstvwHours" HorizontalAlignment="Left" Height="264" Margin="427,77,0,0" VerticalAlignment="Top" Width="357" RightTapped="lstvwHours_RightTapped">
Secondly in Microsoft's context menu code example they say to use the PopupMenu class but in other code I've seen it coded into the XAML.
And lastly After the one context menu button is clicked I want it to fire a delete method.
private async void lstvwHours_RightTapped(object sender,
RightTappedRoutedEventArgs e)
{
var menu = new PopupMenu();
menu.Commands.Add(new UICommand("Delete"/*do I put the method to call here?*/));
var chosenCommand = await menu.ShowForSelectionAsync(GetElementRect((FrameworkElement)sender));
}
Here's an example.
In this case you can wire-up the commands that get invoked from your menuitem onto your view-model.
<ListView>
<ListViewItem Content="One">
<ListViewItem.ContextMenu>
<ContextMenu>
<MenuItem Header="Insert"
Command="{Binding DataContext.InsertQuery, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"/>
<MenuItem Header="Delete"
Command="{Binding DataContext.DeleteQuery, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"/>
</ContextMenu>
</ListViewItem.ContextMenu>
</ListViewItem>
</ListView>

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>

Having multiple Controls using the same CommandBinding in WPF?

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

Executing a Command when a ListView is DoubleClicked. (WPF - MVVM)

I am having some difficulties binding a command (ICommand) to the MouseBinding of a ListView.
I used this piece of XAML code to test the different mouse gestures:
<ListView.InputBindings>
<MouseBinding Command="{Binding OpenSOACommand}" Gesture="LeftClick" />
<MouseBinding Command="{Binding OpenSOACommand}" Gesture="MiddleClick" />
<MouseBinding Command="{Binding OpenSOACommand}" Gesture="LeftDoubleClick" />
</ListView.InputBindings>
The LeftClick and LeftDoubleClick gestures aren't triggered, yet the MiddleClick mouse binding works perfect (I have tested the mouse bindings one at a time as well...).
Is there a difference in the way the LeftDoubleClick and MiddleClick Gesture is handled? And if there is, how can I bind my ICommand to the LeftDoubleClick gesture?
Thanks!
The default Click event for the ListView is marking the event as handled. Try using PreviewLeftClick and PreviewLeftDoubleClick instead
EDIT
Since MouseBindings does not contain a PreviewLeftClick or PreviewLeftDoubleClick, try using the AttachedCommandBehavior code found here which allows you to attach a Command to just about any Event
For example,
<ListView local:CommandBehavior.Event="PreviewMouseDown"
local:CommandBehavior.Command="{Binding OpenSOACommand}" />
This is because your ListViewItems of your ListView will swallow your LeftClick events and convert them into nice SelectionChanged events. Since the ListViewItems will not respond to MiddleClick, this will work as expected.
You might want to get 'in front' of this click by handling the matching Preview equivalent of the event.
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<EventSetter Event="MouseDoubleClick" Handler="OnItemDoubleClick"/>
</Style>
</ListView.ItemContainerStyle>
And invoke the command in the handler:
private void OnItemDoubleClick(object sender, MouseButtonEventArgs e)
{
OpenSOACommand.Execute(null, this);
}

How to add access keys to menu items?

<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.

Categories