从ContextMenu中的MenuItem绑定ElementName

Jos*_*h G 66 data-binding wpf contextmenu elementname

是否有人注意到带有ElementName的Bindings无法正确解析MenuItem对象中包含的ContextMenu对象?看看这个样本:

<Window x:Class="EmptyWPF.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="window">
    <Grid x:Name="grid" Background="Wheat">
        <Grid.ContextMenu>
            <ContextMenu x:Name="menu">
                <MenuItem x:Name="menuItem" Header="Window" Tag="{Binding ElementName=window}" Click="MenuItem_Click"/>
                <MenuItem Header="Grid" Tag="{Binding ElementName=grid}" Click="MenuItem_Click"/>
                <MenuItem Header="Menu" Tag="{Binding ElementName=menu}" Click="MenuItem_Click"/>
                <MenuItem Header="Menu Item" Tag="{Binding ElementName=menuItem}" Click="MenuItem_Click"/>
            </ContextMenu>
        </Grid.ContextMenu>
        <Button Content="Menu" 
                HorizontalAlignment="Center" VerticalAlignment="Center" 
                Click="MenuItem_Click" Tag="{Binding ElementName=menu}"/>
        <Menu HorizontalAlignment="Center" VerticalAlignment="Bottom">
            <MenuItem x:Name="anotherMenuItem" Header="Window" Tag="{Binding ElementName=window}" Click="MenuItem_Click"/>
            <MenuItem Header="Grid" Tag="{Binding ElementName=grid}" Click="MenuItem_Click"/>
            <MenuItem Header="Menu" Tag="{Binding ElementName=menu}" Click="MenuItem_Click"/>
            <MenuItem Header="Menu Item" Tag="{Binding ElementName=anotherMenuItem}" Click="MenuItem_Click"/>
        </Menu>
    </Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

除了ContextMenu中包含的绑定之外,所有绑定都很有效.它们在运行时将错误输出到"输出"窗口.

有谁知道任何工作?这里发生了什么?

Jos*_*h G 54

我找到了一个更简单的解决方案.

在UserControl背后的代码中:

NameScope.SetNameScope(contextMenu, NameScope.GetNameScope(this));
Run Code Online (Sandbox Code Playgroud)

  • 适用于4.5.2.小心......它使用"ElementName"修复绑定,但它不使用"RelativeSource FindAncestor"修复绑定. (4认同)

Mar*_*arc 23

正如其他人所说,'ContextMenu'不包含在可视树中,'ElementName'绑定不起作用.如果在"DataTemplate"中未定义上下文菜单,则仅按接受的答案建议设置上下文菜单的"NameScope".我通过使用类似于'ElementName'绑定的{x:Reference}标记扩展来解决这个问题,但绕过可视树以不同方式解析绑定.我认为这比使用'PlacementTarget'更具可读性.这是一个例子:

<Image Source="{Binding Image}">       
    <Image.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Delete" 
                      Command="{Binding Source={x:Reference Name=Root}, Path=DataContext.RemoveImage}"
                      CommandParameter="{Binding}" />
        </ContextMenu>
    </Image.ContextMenu>
</Image>
Run Code Online (Sandbox Code Playgroud)

根据MSDN文档

x:Reference是在XAML 2009中定义的构造.在WPF中,您可以使用XAML 2009功能,但仅适用于非WPF标记编译的XAML.标记编译的XAML和BAML形式的XAML目前不支持XAML 2009语言关键字和功能.

无论那意味着什么......但对我而言.

  • 其实这里最有用的评论 (4认同)
  • 如果“Root”对象是“MenuItem”的父对象,则在运行时会失败,并显示错误“由于循环依赖而无法调用 MarkupExtension.ProvideValue”。 (4认同)

小智 20

这是另一个仅限xaml的解决方法.(这也假设你想要DataContext中的内容,例如,你是MVVM的)

选项一,其中ContextMenu的父元素不在DataTemplate中:

Command="{Binding PlacementTarget.DataContext.MyCommand, 
         RelativeSource={RelativeSource AncestorType=ContextMenu}}"
Run Code Online (Sandbox Code Playgroud)

这对OP的问题很有用.如果您在DataTemplate中,这将不起作用.在这些情况下,DataContext通常是集合中的众多元素之一,并且您希望绑定的ICommand是同一ViewModel(例如Window 的DataContext)中集合的兄弟属性.

在这些情况下,您可以利用Tag暂时保存包含集合和ICommand 的父DataContext:

class ViewModel
{
    public ObservableCollection<Derp> Derps { get;set;}
    public ICommand DeleteDerp {get; set;}
} 
Run Code Online (Sandbox Code Playgroud)

并在xaml

<!-- ItemsSource binds to Derps in the DataContext -->
<StackPanel
    Tag="{Binding DataContext, ElementName=root}">
    <StackPanel.ContextMenu>
        <ContextMenu>
            <MenuItem
                Header="Derp"                       
                Command="{Binding PlacementTarget.Tag.DeleteDerp, 
                RelativeSource={RelativeSource 
                                    AncestorType=ContextMenu}}"
                CommandParameter="{Binding PlacementTarget.DataContext, 
                RelativeSource={RelativeSource AncestorType=ContextMenu}}">
            </MenuItem>
Run Code Online (Sandbox Code Playgroud)


Jos*_*osh 5

上下文菜单很难绑定.它们存在于您的控件的可视树之外,因此无法找到您的元素名称.

尝试将上下文菜单的datacontext设置为其放置目标.你必须使用RelativeSource.

<ContextMenu 
   DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}"> ...
Run Code Online (Sandbox Code Playgroud)