【问题标题】:How to bind MenuItem.Header to Window/UserControl dependency property?如何将 MenuItem.Header 绑定到 Window/UserControl 依赖属性?
【发布时间】:2011-04-25 18:28:24
【问题描述】:

我想知道如何将 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); }
    }
}

在我的例子中,文本块显示“项目 1”,上下文菜单显示空项目。我做错了什么?在我看来,我面临着对 WPF 数据绑定原则的严重误解。

【问题讨论】:

    标签: wpf data-binding


    【解决方案1】:

    你应该在 Visual Studio 的输出窗口中看到这个:

    System.Windows.Data 错误:4:不能 通过参考查找绑定源 '元素名 = 自我'。 绑定表达式:路径=菜单文本; 数据项=空;目标元素是 '菜单项'(名称='');目标属性 是“标题”(类型“对象”)

    那是因为 ContextMenu 和 VisualTree 断开了,你需要做这个 Binding 不同。

    一种方法是通过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),您可以尝试通过 Grid 的 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>
    

    【讨论】:

    • 能否请您说明如何通过标签传递对 Window/UserControl 的引用?如果我使用 Tag="{x:Reference self}" 语法,我会收到编译错误 "XML 命名空间 'schemas.microsoft.com/winfx/2006/xaml' 中不存在标签 'Reference'。 我使用 VS2008 和 .NET框架 3.5.
    • 仅存在于 .NET 4 中,您应该可以使用 Binding 代替,例如 Tag="{Binding ElementName=self}"
    【解决方案2】:

    HB 解决方案的替代方案是这种附加行为:ContextMenuServiceExtensions.DataContext Attached Property

    【讨论】:

      猜你喜欢
      • 2023-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-29
      • 2014-08-31
      • 2017-12-24
      • 2017-12-18
      相关资源
      最近更新 更多