目标: 右键单击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>
答案 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}}">