WPF按钮带有上下文菜单,如何将上下文菜单的宽度绑定到按钮的宽度?

4
我有一个简单的按钮,在这个按钮上,我希望上下文菜单的宽度与按钮的宽度相同(我想让按钮的左键单击直接在按钮下方打开上下文菜单)。
<Button x:Name="btn" Content="Push Me">
    <Button.ContextMenu>
        <ContextMenu x:Name="cm">
            <MenuItem Header="One" />
            <MenuItem Header="Two" />
            <MenuItem Header="Three" />
        </ContextMenu>
    </Button.ContextMenu>
</Button>

我尝试在上下文菜单本身上绑定以下内容,但它不起作用。
<ContextMenu x:Name="cm" Width="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Button}}, Path=ActualWidth}">

但是,我已经在代码中成功地使它工作了。

btn.LayoutUpdated += (s, e) => cm.Width = btn.ActualWidth;

我的问题是...是否存在一个XAML绑定,可以为我提供这个功能?
2个回答

5

ContextMenu有一个名为PlacementTarget的属性,这个属性在本例中将是Button,所以你可以尝试在Binding的路径中使用它。

<ContextMenu x:Name="cm"
             Width="{Binding RelativeSource={RelativeSource Self},
                             Path=PlacementTarget.ActualWidth}">

@Jon 请记住,任何位于 PlacementTarget(Button)之外的内容都必须通过搜索可视树来进行调整...因此需要调整 NameScope,但这种解决方案对于您的情况肯定是理想的。 - Aaron McIver
@Aaron,明白了,这只能让我访问到按钮,但如果我想要访问父级StackPanel或其他什么东西,那么我就需要搜索树结构。 - Jon Erickson

2
这与 ContextMenu 与其 NameScope 的行为方式有关。如果您在调试器中分析 ContextMenu,则会注意到它的父级是 Popup,而 Popup 的父级为空。

MSDN 论坛上提到的其中一种 解决方法 是调整 NameScope,这将允许 ContextMenu 表现出您期望的行为。

    NameScope.SetNameScope(this, new NameScope());

这显然会在代码后台进行,就像您的另一种方法一样;两者都不是最佳选择。

谢谢您的见解,这是我第一次使用WPF,我需要尽可能多的见解 =) - Jon Erickson
+1 对你的回答表示赞赏,我不知道你可以像那样设置 NameScope,这很好知道! - Fredrik Hedblad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接