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

时间:2021-07-09 06:03:18

This seems to be a pretty popular topic, but...

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

I have the following XAML:

我有以下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>

Now, MyCommandObject is a control which exposes dynamic commands from its DataContext. You know what's coming next. :)

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

Basically, the button command works perfectly - when I click it, the DoAction command on the MyCommandObject gets executed perfectly. However, the command in the menuitem doesn't get executed. I've tried various tricks such as setting the context menu datacontext to be the placementTarget so it can traverse the visual tree of the controls and so on, but nothing's doing.

基本上,按钮命令工作正常 - 当我单击它时,MyCommandObject上的DoAction命令被完美地执行。但是,menuitem中的命令不会被执行。我尝试了各种技巧,例如将上下文菜单datacontext设置为placementTarget,以便它可以遍历控件的可视树等等,但没有做任何事情。

What particular alignment of RelativeSource and CommandTarget runes do I need to get this to work?

我需要使用哪种特定的RelativeSource和CommandTarget符号来使其工作?

1 个解决方案

#1


4  

This is happening because DataContext="{Binding PlacementTarget,... binding would set the button as MenuItems DataContext but that won't add the ContextMenu to the VisualTree of your window and that's why ElementName binding's won't work. A simple workaround to use ElementName bindings is to add this in your Window/UserControl's code-behind:

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

NameScope.SetNameScope(contextMenuName, NameScope.GetNameScope(this)); 

Another solution is to do this -

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

<ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">   
    <MenuItem Command="{Binding DataContext.DoAction}"/>   
</ContextMenu>

DataContext="{Binding PlacementTarget,... will set the Button(Placementtarget) as the DataContext of your ContextMenu, so you can use Button's DataContext to bind command.

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

Update:

更新:

You can try and use the NameScope.NameScope Attached Property to set NameScope in XAML but I am not sure how you will get the NameScope of parent window without code!

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

You will have to do something similar to following article by Josh Smith, he provides a way to do this in XAML; but that too involves code (more then that single line of code) -

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

Enable ElementName Bindings with ElementSpy

使用ElementSpy启用ElementName绑定

Any specific reason to not use this single line of code?

有什么特别的理由不使用这一行代码吗?

#1


4  

This is happening because DataContext="{Binding PlacementTarget,... binding would set the button as MenuItems DataContext but that won't add the ContextMenu to the VisualTree of your window and that's why ElementName binding's won't work. A simple workaround to use ElementName bindings is to add this in your Window/UserControl's code-behind:

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

NameScope.SetNameScope(contextMenuName, NameScope.GetNameScope(this)); 

Another solution is to do this -

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

<ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">   
    <MenuItem Command="{Binding DataContext.DoAction}"/>   
</ContextMenu>

DataContext="{Binding PlacementTarget,... will set the Button(Placementtarget) as the DataContext of your ContextMenu, so you can use Button's DataContext to bind command.

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

Update:

更新:

You can try and use the NameScope.NameScope Attached Property to set NameScope in XAML but I am not sure how you will get the NameScope of parent window without code!

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

You will have to do something similar to following article by Josh Smith, he provides a way to do this in XAML; but that too involves code (more then that single line of code) -

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

Enable ElementName Bindings with ElementSpy

使用ElementSpy启用ElementName绑定

Any specific reason to not use this single line of code?

有什么特别的理由不使用这一行代码吗?