如何通过可视树从ContextMenu menuitem访问控件?

Web*_*per 6 wpf xaml binding contextmenu relativesource

这似乎是一个非常受欢迎的话题,但......

我有以下XAML:

<internal:MyCommandObject x:Name="CommandModel"/>

<Button DockPanel.Dock="Bottom" Command="{Binding DoAction, ElementName=CommandModel}">
    <Button.ContextMenu>
        <ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
            <MenuItem Command="{Binding DoAction, ElementName=CommandModel}"/>
        </ContextMenu>
    </Button.ContextMenu>
    Click Me
</Button>
Run Code Online (Sandbox Code Playgroud)

现在,MyCommandObject是一个从其公开动态命令的控件DataContext.你知道接下来会发生什么.:)

基本上,按钮命令工作正常 - 当我单击它时,DoAction命令就MyCommandObject完美地执行了.但是,menuitem中的命令不会被执行.我尝试过各种手段,例如设置上下文菜单datacontextplacementTarget这样它可以遍历控制等的可视化树,但没有在做.

我需要什么特定的对齐RelativeSourceCommandTarget符文才能使它工作?

akj*_*shi 3

发生这种情况是因为DataContext="{Binding PlacementTarget,...绑定会将按钮设置为 MenuItems DataContext,但这不会将按钮添加ContextMenu到窗口的 VisualTree,这就是ElementName绑定不起作用的原因。使用ElementName绑定的一个简单解决方法是将其添加到 Window/UserControl 的代码隐藏中:

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

另一个解决方案是这样做 -

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

DataContext="{Binding PlacementTarget,...会将 Button(Placementtarget) 设置为 ContextMenu 的 DataContext,因此您可以使用 Button 的 DataContext 来绑定命令。

更新:

您可以尝试使用NameScope.NameScope附加属性在 XAML 中设置 NameScope,但我不确定如何在没有代码的情况下获取父窗口的 NameScope!

您必须执行类似于 Josh Smith 的以下文章的操作,他提供了一种在 XAML 中执行此操作的方法;但这也涉及代码(不仅仅是那一行代码)-

使用 ElementSpy 启用 ElementName 绑定

有什么具体原因不使用这一行代码吗?