我想知道如何将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>
Run Code Online (Sandbox Code Playgroud)
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); }
}
}
Run Code Online (Sandbox Code Playgroud)
在我的例子中,textblock显示"Item 1",上下文菜单显示空项.我做错了什么?在我看来,我遇到了严重的WPF数据绑定原则的误解.
您应该在Visual Studio的"输出"窗口中看到:
System.Windows.Data错误:4:无法找到引用'ElementName = self'的绑定源.BindingExpression:路径= MenuText; 的DataItem = NULL; target元素是'MenuItem'(Name =''); target属性是'Header'(类型'Object')
这是因为ContextMenu与VisualTree断开连接,您需要以不同方式执行此绑定.
一种方法是via ContextMenu.PlacementTarget
(应该是Grid),你可以使用它的DataContext来建立绑定,例如:
<MenuItem Header="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.DataContext.MenuText}"/>
Run Code Online (Sandbox Code Playgroud)
或者在ContextMenu中设置DataContext:
<ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.DataContext}">
<MenuItem Header="{Binding Path=MenuText}"/>
</ContextMenu>
Run Code Online (Sandbox Code Playgroud)
如果这不是一个选项(因为Grid的DataContext不能是Window/UserControl),您可以尝试通过Tag
Grid的方式将引用传递给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>
...
Run Code Online (Sandbox Code Playgroud)
作为旁注:由于这种行为,我倾向于定义一个帮助器样式,App.xaml
以使所有ContextMenus从其父级"伪继承"DataContext:
<!-- Context Menu Helper -->
<Style TargetType="{x:Type ContextMenu}">
<Setter Property="DataContext" Value="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"/>
</Style>
Run Code Online (Sandbox Code Playgroud)