WPF: Binding a ContextMenu to an MVVM Command
The problem is that the ContextMenu it not in the visual tree, so you basically have to tell the Context menu about which data context to use.
Check out this blogpost with a very nice solution of Thomas Levesque.
He creates a class Proxy that inherits Freezable and declares a Data dependency property.
public class BindingProxy : Freezable
{
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}
Then it can be declared in the XAML (on a place in the visual tree where the correct DataContext is known):
<Grid.Resources>
<local:BindingProxy x:Key="Proxy" Data="{Binding}" />
</Grid.Resources>
And used in the context menu outside the visual tree:
<ContextMenu>
<MenuItem Header="Test" Command="{Binding Source={StaticResource Proxy}, Path=Data.MyCommand}"/>
</ContextMenu>
WPF Context Menu command Binding
Have changed my XAML to,
<Window.Resources>
<local:ImageList x:Key="SliderViewModel"></local:ImageList>
</Window.Resources>
<Image Source="{Binding CurrentImage.Source, Mode=OneWay}" Grid.Row="0" Grid.Column="1">
<Image.ContextMenu>
<ContextMenu>
<MenuItem Header="Edit Image" Command="{Binding EditImageCommand, Source={StaticResource SliderViewModel}}"></MenuItem>
</ContextMenu>
</Image.ContextMenu>
</Image>
Working fine. Thanks
MVVM How to bind command to ContextMenu
You can't use RelativeSource in ContextMenu, because the menu is not a part of the visual tree. However this can be avoided by using Binding Source and x:Reference.
I assume your ViewModel looks like this
public class UserViewModel
{
public string Header { get; set; }
public ICommand MyCommand { get; }
... more code
}
Now let's bind Header and MyCommand properties of the VM
<ContextMenu x:Key="ContextMenu">
<ContextMenu.Items>
<MenuItem Header="{Binding Header, Source={x:Reference vm}}"
Command="{Binding MyCommand, Source={x:Reference vm}}"/>
</ContextMenu.Items>
</ContextMenu>
The important part is to have the ViewModel somewhere in the visual tree and set its x:Name, just like you've done in your example
<Page.DataContext>
<PDB:UsersViewModel x:Name="vm"/>
</Page.DataContext>
If you still want to know more about RelativeSource, this question seems to have the same problem as you. Basically Path of the binding has to be DataContext.MyViewModelProperty
and the RelativeSource of the binding must be and element with DataContext set to the ViewModel.
MVVM binding command to contextmenu item
(Edit) Since you mentioned this is in an ItemsControl's template, things are different:
1) Get the BindingProxy class from this blog (and read the blog, as this is interesting information): How to bind to data when the DataContext is not inherited.
Basically the elements in the ItemsControl (or ContextMenu) are not part of the visual or logical tree, and therefore cannot find the DataContext of your UserControl. My apologies for not writing more on this here, but the author has done a good job explaining it step by step, so there's no way I could give a complete explanation in just a few lines.
2) Do something like this: (you may have to adapt it a bit to make it work in your control):
a. This will give you access to the UserControl DataContext using a StaticResource:
<UserControl.Resources>
<BindingProxy
x:Key="DataContextProxy"
Data="{Binding}" />
</UserControl.Resources>
b. This uses the DataContextProxy defined in (a):
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove" CommandParameter="{Binding Name}"
Command="{Binding Path=Data.RemoveCommand, Source={StaticResource DataContextProxy}}"/>
</ContextMenu>
This has worked for us in things like trees and datagrids.
WPF binding command to ContextMenu
I had a similar problem before and solved it by passing the datacontext through the tag property of the container as below. I have it working on a grid ContextMenu but dont see any reason why this wont work on a button. Let me know if you have any problem
<Button Content="qwerty" Tag="{Binding DataContext,ElementName=Lst}" Command="{Binding ElementName=Lst, Path=DataContext.SaveCommand}" >
<Button.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Send2" Command="{Binding SaveCommand}" />
</ContextMenu>
</Button.ContextMenu>
</Button>
How do I bind to a context MenuItem header in WPF MVVM?
You can only bind to properties, not fields.
public string HeaderText {get; set;}
Binding command of parent control to ContextMenu MenuItem
You can access the ViewModelLocator
inside the ItemTemplate
as well.
<DataGrid Grid.Column="0">
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Add template..." ItemsSource="{Binding JobTemplates}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Name}" Command="{Binding Source={StaticResource Locator}, Path=Main.AddTemplateJobCommand}" CommandParameter="{Binding Name}"/>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
A more general approach without MVVM light could be using a binding proxy.
Related Topics
Custom Collection Initializers
Thread.Sleep for Less Than 1 Millisecond
How to Filter "Include" Entities in Entity Framework
Newtonsoft.JSON Cannot Convert Model with Typeconverter Attribute
Why Should I Use Int Instead of a Byte or Short in C#
Listen to Changes of Dependency Property
Capture Screenshot Including Semitransparent Windows in .Net
How to Justify Text in a Label
Reset the Value of Textarea After Form Submission
JSON Deserialization to C# with Dynamic Keys
How to Get Intptr from Byte[] in C#
Editing Dictionary Values in a Foreach Loop
Foreach VS Somelist.Foreach(){}
Install a .Net Windows Service Without Installutil.Exe
Collection<T> Versus List<T> What Should You Use on Your Interfaces
How to Use a MySQL User Defined Variable in a .Net MySQLcommand