使用ContextMenu时出现问题,不显示项目

时间:2017-01-24 14:45:44

标签: c# wpf data-binding contextmenu

目标: 右键单击ListBox并获取绑定的contextMenu。

public class MyViewModel
{

    public List<string> ContextMenuItems{ get; set; }
    public ItemObject MyObject{ get; set; }
}

public class ItemObject{
    public List<OtherObjects> SomeCollection{ get; set; }
}

现在我的ListBox被绑定到&#34; SomeCollection&#34;,但我的ContextMenu应该访问列表框的Binding之外的Binding。我已经尝试过但根本无法使用它,我的上下文菜单总是空的。知道为什么吗?这是在UserControl而不是Window,而不是它是相关的。我只是指出为什么我的AncestorType指向UserControl

<ListBox ItemsSource="{Binding SomeCollection}">
<ListBox.ContextMenu >
<ContextMenu DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" ItemsSource="{Binding ContextMenuItems}">
    <ContextMenu.ItemTemplate> 
        <DataTemplate>
            <MenuItem Header="{Binding}" Command="{Binding MyCommand}"/>
        </DataTemplate>
    </ContextMenu.ItemTemplate>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>

1 个答案:

答案 0 :(得分:1)

在WPF中绑定上下文菜单是非常棘手的。原因是它们存在于Visual Tree之外的其他组件所做的事情。 (如果你考虑一下,这是有道理的,因为它们在他们自己的弹出窗口中)。

由于它们位于不同的可视化树中,因此能够按名称绑定的有用信息会导致绑定错误,如您所发现的那样。 “无法找到源”意味着它无法在可视化树中找到命名元素。

解决它的一种方法是使用上下文菜单本身的“PlacementTarget”属性。这是指父控件,您可以在其中访问数据上下文:

<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}" ItemsSource="{Binding ContextMenuItems}">

我还发现,如果我做的事情非常复杂,需要在大型上下文菜单中引用多个内容,我希望在代理静态资源中有效地存储我想要访问的内容。

创建自定义代理类:

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));
}

在您的资源中,只要您在访问正确的DataContext时遇到困难,就创建一个代理对象:

<UserControl.Resources>
    <local:BindingProxy x:Key="Proxy" Data="{Binding}" />
</UserControl.Resources>

然后你的xaml中的任何地方都可以轻松访问它:

<ContextMenu ItemsSource="{Binding Data.ContextMenuItems, Source={StaticResource Proxy}}">