Hello,
I have a the following code (Code #1) attached to a XamDataGrid:
<ig:ContextMenuManager> <ig:ContextMenuManager.ContextMenu> <ig:XamContextMenu> <ig:XamMenuItem Header="Edit"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <i:InvokeCommandAction Command="{Binding Path=MyCommand}" /> </i:EventTrigger> </i:Interaction.Triggers> </ig:XamMenuItem> </ig:XamContextMenu> </ig:ContextMenuManager.ContextMenu></ig:ContextMenuManager>where xmlns:ig="http://schemas.infragistics.com/xaml" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"The command does not work as intended, nothing is being shown.The following code (Code #2) works as intended:<Button Content="Save" Height="20"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <i:InvokeCommandAction Command="{Binding Path=MyCommand}"/> </i:EventTrigger> </i:Interaction.Triggers> </Button>When I change MyCommand in Code #2 to MyCommand2 (which doesn't exist) it tries to find the property MyCommand2 on the DataContextMyCommand does actually exist on the DataContext (as shown on Code #2)The command actually isprivate ICommand _myCommand;public ICommand MyCommand{ get { return _myCommand ?? (_myCommand = new RelayCommand(param => MessageBox.Show("TEST!"))); } }I'm using the MVVM architecture.Why doesn't the Code #1 work? Any ideas?Thank you!
You're right. It looks like the InvokeCommandAction Behavior fails to work in a XamMenuItem in a XamContextMenu. I've reported this as a bug and it is assigned Case ID: CAS-63623-2YJ4B9.
I apologize for the inconvenience!
I spoke with development on this issue.
A xamContextMenu isn't in the VisualTree, and thus doesn't partake in the DataContext inheritance. The wpf Contextmenu will work because it is in the visualTree.
To get this to work, your binding would need a Source set to a StaticResource for the command.
Valerie
Thank you!
Since the declaration of the XamContextMenu acts like a DataTemplate in that it is not part of the Visual Tree, it does not have access to the DataContext of the view it is embedded in. The way around this is to instantiate the ViewModel source in the ResourceDictionary of the container. Then you can access this data source directly and apply it to the Command Binding expression directly.
<Window.Resources> <local:MainViewModel x:Key="ViewModelDataSource" /></Window.Resources>....<i:InvokeCommandAction Command="{Binding Path=MyCommand, Source={StaticResource ViewModelDataSource}}"/>
I've attached a sample to demonstrate.
The approach above suggested by Curtis works but not with a VM with a parameterised constructor. If you are wiring up ViewModels with MEF or some IoC container like Unity you may run into issues with this solution.
I have come up with a work-around for Silverlight but it should work with WPF as well.
I create a class that derives from XamContextMenu, override the OnApplyTemplate() method then if the DataContext is null it gets assigned from the 'PlacementTargetAssigned' property's DataContext: this is usually the containing control.
I also create a derived XamContextMenuItem class that has a Command DependencyProperty which is executed on the item clicked event.
code as below (apologies for the formatting):
public class CustomContextMenu : XamContextMenu { public override void OnApplyTemplate() { if (DataContext == null) { var frameworkElement = PlacementTargetResolved as FrameworkElement; if (frameworkElement != null) { DataContext = frameworkElement.DataContext; } } base.OnApplyTemplate(); } }
///
/// A class that extends XamMenuItem by adding a 'Command' property for MVVM. /// public class CustomMenuItem : XamMenuItem {public const string CommandPropertyName = "Command";
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(CommandPropertyName, typeof(ICommand), typeof(CustomMenuItem), null);
public ICommand Command { get { return (ICommand)GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } }
public override void OnApplyTemplate() { InitEvents(); base.OnApplyTemplate(); }
private void InitEvents() { Click -= CustomMenuItem_Click; Click += CustomMenuItem_Click; }
void CustomMenuItem_Click(object sender, System.EventArgs e) { if (Command != null) Command.Execute(null); } }
It has been a while since you have made your post, in case you still need support I will be glad to assist you further. I suppose the other community members can benefit from this answer as well. I have been looking into your post and I can say that the XamContextMenu still works the same way as before, so if you want to follow the MVVM pattern you should use Interactions and you should set the Binding's Source.
was this issue ever solved with the menus? Still showing the same behavior
Hi there,
To access this DLL you need to install either the Expression Blend SDK or Expression Blend itself:
Blend 3 SDK:http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=22829
Blend 4 SDKhttp://www.microsoft.com/download/en/details.aspx?id=10801
Once installed, the default location for System.Windows.Interactivity will be one of the following: C:\Program Files\Microsoft SDKs\Expression\Blend\Interactivity\Libraries\WPF\C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\Interactivity\Libraries\WPF\
C:\Program Files\Microsoft SDKs\Expression\Blend\.NETFramework\v4.0\Libraries\C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\.NETFramework\v4.0\Libraries\
FYI: Silverlight will have its own version of this DLL in a similar location.
Curtis,
Great solution but am facing one issue while implementing.I cant see the command property of InvokeCommandAction
The namespace am using is
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
and dll is System.Windows.Interactivity v2.0.50727
Could you please help.
Thanks
Vivek