I'm having some difficulty with Context Menu commands on my View Model.
I'm implementing the ICommand interface for each command within the View Model, then creating a ContextMenu within the resources of the View (MainWindow), and using a CommandReference from the MVVMToolkit to access the current DataContext (ViewModel) Commands.
When I debug the application, it appears that the CanExecute method on the command is not being called except at the creation of the window, therefore my Context MenuItems are not being enabled or disabled as I would have expected.
I've cooked up a simple sample (attached here) which is indicative of my actual application and summarised below. Any help would be greatly appreciated!
This is the ViewModel
namespace WpfCommandTest
{
public class MainWindowViewModel
{
private List<string> data = new List<string>{ "One", "Two", "Three" };
// This is to simplify this example - normally we would link to
// Domain Model properties
public List<string> TestData
{
get { return data; }
set { data = value; }
}
// Bound Property for listview
public string SelectedItem { get; set; }
// Command to execute
public ICommand DisplayValue { get; private set; }
public MainWindowViewModel()
{
DisplayValue = new DisplayValueCommand(this);
}
}
}
The DisplayValueCommand is such:
public class DisplayValueCommand : ICommand
{
private MainWindowViewModel viewModel;
public DisplayValueCommand(MainWindowViewModel viewModel)
{
this.viewModel = viewModel;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
if (viewModel.SelectedItem != null)
{
return viewModel.SelectedItem.Length == 3;
}
else return false;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
MessageBox.Show(viewModel.SelectedItem);
}
#endregion
}
And finally, the view is defined in Xaml:
<Window x:Class="WpfCommandTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCommandTest"
xmlns:mvvmtk="clr-namespace:MVVMToolkit"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<mvvmtk:CommandReference x:Key="showMessageCommandReference" Command="{Binding DisplayValue}" />
<ContextMenu x:Key="listContextMenu">
<MenuItem Header="Show MessageBox" Command="{StaticResource showMessageCommandReference}"/>
</ContextMenu>
</Window.Resources>
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<ListBox ItemsSource="{Binding TestData}" ContextMenu="{StaticResource listContextMenu}"
SelectedItem="{Binding SelectedItem}" />
</Grid>
</Window>
To complete Will's answer, here's a "standard" implementation of the CanExecuteChanged
event :
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
(from Josh Smith's RelayCommand
class)
By the way, you should probably consider using RelayCommand
or DelegateCommand
: you'll quickly get tired of creating new command classes for each and every command of you ViewModels...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With