一尘不染

WPF:将ContextMenu绑定到MVVM命令

c#

假设我有一个窗口,该窗口的属性返回一个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, ...}代替,但是会产生类似的错误消息。


阅读 756

收藏
2020-05-19

共1个答案

一尘不染

问题在于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>
2020-05-19