Let's say I have a Window with a property returning a Command (in fact, it's a UserControl with a Command in a ViewModel class, but let's keep things as simple as possible to reproduce the problem).
The following works:
<Window x:Class="Window1" ... x:Name="myWindow"> <Menu> <MenuItem Command="{Binding MyCommand, ElementName=myWindow}" Header="Test" /> </Menu> </Window>
But the following does not work.
<Window x:Class="Window1" ... x:Name="myWindow"> <Grid> <Grid.ContextMenu> <ContextMenu> <MenuItem Command="{Binding MyCommand, ElementName=myWindow}" Header="Test" /> </ContextMenu> </Grid.ContextMenu> </Grid> </Window>
The error message I get is
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=myWindow'. BindingExpression:Path=MyCommand; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'Command' (type 'ICommand')
Why? And how do I fix this? Using the DataContext
is not an option, since this problem occurs way down the visual tree where the DataContext already contains the actual data being displayed. I already tried using {RelativeSource FindAncestor, ...}
instead, but that yields a similar error message.
The command is the action to be executed. The command source is the object which invokes the command. The command target is the object that the command is being executed on. The command binding is the object which maps the command logic to the command.
Commands are an implementation of the ICommand interface that is part of the . NET Framework. This interface is used a lot in MVVM applications, but it is useful not only in XAML-based apps.
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>
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