我想知道如何将MenuItem.Header绑定到父Window / UserControl依赖项属性?这是一个简单的例子:
Window1.xaml :
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300" x:Name="self">
<Grid>
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="{Binding Path=MenuText, ElementName=self}" />
</ContextMenu>
</Grid.ContextMenu>
<TextBlock Text="{Binding Path=MenuText, ElementName=self}"/>
</Grid>
</Window>
Window1.xaml.cs :
public partial class Window1 : Window {
public static readonly DependencyProperty MenuTextProperty = DependencyProperty.Register(
"MenuText", typeof (string), typeof (Window1), new PropertyMetadata("Item 1"));
public Window1()
{
InitializeComponent();
}
public string MenuText {
get { return (string)this.GetValue(MenuTextProperty); }
set { this.SetValue(MenuTextProperty, value); }
}
}
在我的例子中,textblock显示“Item 1”,上下文菜单显示空项。我做错了什么?在我看来,我遇到了严重的WPF数据绑定原则的误解。
答案 0 :(得分:7)
您应该在Visual Studio的“输出”窗口中看到这一点:
System.Windows.Data错误:4:不能 找到与参考绑定的源 '的ElementName =自我'。 BindingExpression:路径= MenuText; 的DataItem = NULL;目标元素是 'MenuItem'(Name ='');目标财产 是'标题'(类型'对象')
那是因为ContextMenu与VisualTree断开连接,你需要以不同的方式进行绑定。
一种方法是通过ContextMenu.PlacementTarget
(应该是Grid),你可以使用它的DataContext来建立绑定,例如:
<MenuItem Header="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.DataContext.MenuText}"/>
或在ContextMenu中设置DataContext:
<ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.DataContext}">
<MenuItem Header="{Binding Path=MenuText}"/>
</ContextMenu>
如果这不是一个选项(因为Grid的DataContext不能是Window / UserControl),您可以尝试通过网格的Tag
将引用传递给Window / UserControl。
<Grid ...
Tag="{x:Reference self}">
<Grid.ContextMenu>
<!-- The DataContext is now bound to PlacementTarget.Tag -->
<ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.Tag}">
<MenuItem Header="{Binding Path=MenuText}"/>
</ContextMenu>
...
作为旁注:由于这种行为,我倾向于在App.xaml
中定义一个帮助器样式,以使所有ContextMenus从其父级“伪继承”DataContext:
<!-- Context Menu Helper -->
<Style TargetType="{x:Type ContextMenu}">
<Setter Property="DataContext" Value="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"/>
</Style>
答案 1 :(得分:1)
H.B.解决方案的替代方案是这种附加行为:ContextMenuServiceExtensions.DataContext Attached Property