假设我有一个窗口,该窗口的属性返回一个Command(实际上,它是ViewModel类中的一个带Command的UserControl,但是让事情尽可能简单以重现该问题)。
以下作品:
<Window x:Class="Window1" ... x:Name="myWindow"> <Menu> <MenuItem Command="{Binding MyCommand, ElementName=myWindow}" Header="Test" /> </Menu> </Window>
但是以下方法不起作用。
<Window x:Class="Window1" ... x:Name="myWindow"> <Grid> <Grid.ContextMenu> <ContextMenu> <MenuItem Command="{Binding MyCommand, ElementName=myWindow}" Header="Test" /> </ContextMenu> </Grid.ContextMenu> </Grid> </Window>
我收到的错误消息是
System.Windows.Data错误:4:找不到参考’ElementName = myWindow’的绑定源。BindingExpression:Path = MyCommand; DataItem = null; 目标元素是’MenuItem’(Name =’‘); 目标属性为“命令”(类型为“ ICommand”)
为什么?我该如何解决呢?使用DataContext是不是一种选择,因为出现一路下滑,其中的DataContext已经包含正在显示的实际数据的可视化树这个问题。我已经尝试使用它{RelativeSource FindAncestor, ...}代替,但是会产生类似的错误消息。
DataContext
{RelativeSource FindAncestor, ...}
问题在于ContextMenu不在视觉树中,因此您基本上必须告诉Context菜单要使用的数据上下文。
查阅这篇博客,了解Thomas Levesque的一个很好的解决方案。
他创建了一个类Proxy,该类继承Freezable并声明了Data依赖项属性。
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)); }
然后可以在XAML中(在可视树中已知正确的DataContext的位置上)声明它:
<Grid.Resources> <local:BindingProxy x:Key="Proxy" Data="{Binding}" /> </Grid.Resources>
并在可视树外的上下文菜单中使用:
<ContextMenu> <MenuItem Header="Test" Command="{Binding Source={StaticResource Proxy}, Path=Data.MyCommand}"/> </ContextMenu>