wpf - 如何在此代码中将 contextMenu 放在按钮下?
问题描述
我想获得像 AX 中的按钮,其中一些按钮只打开一个菜单,下面有更多菜单项。我找到了下面的代码,它工作正常。但是当我左键单击按钮时,它会显示鼠标指针所在的上下文菜单。当我右键单击按钮时,它会很好地在按钮下方显示上下文菜单。我希望左键单击像右键单击一样工作。
问题是ContextMenuService.Placement="Bottom"
只有在我右键单击时才有效。
<Button Name="MainButton" Content="Button with ContextMenu" Width="150" Height="30" ContextMenuService.Placement="Bottom">
<Button.ContextMenu>
<ContextMenu x:Name="MainContextMenu" PlacementRectangle="{Binding RelativeSource={RelativeSource self}}">
<MenuItem Header="Do A" />
<MenuItem Header="Do B" />
<MenuItem Header="Do C" />
</ContextMenu>
</Button.ContextMenu>
<Button.Triggers>
<EventTrigger SourceName="MainButton" RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="MainContextMenu" Storyboard.TargetProperty="(ContextMenu.IsOpen)">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<system:Boolean>True</system:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
解决方案
使用 aStoryboard
来设置单个属性值是很奇怪的。这可行,但看起来有些难看。
但这也是您的ContextMenuService.Placement="Bottom"
设置不起作用的原因:您只是没有通过 调用ContextMenuService
打开上下文菜单Storyboard
,因此PlacementTarget
不会将 设置为您的按钮。
我建议您创建一个简单的附加属性并在您的视图中重新使用它:
static class ContextMenuTools
{
public static readonly DependencyProperty OpenOnLeftClickProperty =
DependencyProperty.RegisterAttached(
"OpenOnLeftClick",
typeof(bool),
typeof(ContextMenuTools),
new PropertyMetadata(false, OpenOnLeftClickChanged));
public static void SetOpenOnLeftClick(UIElement element, bool value)
=> element.SetValue(OpenOnLeftClickProperty, value);
public static bool GetOpenOnLeftClick(UIElement element)
=> (bool)element.GetValue(OpenOnLeftClickProperty);
private static void OpenOnLeftClickChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is IInputElement element && (bool)e.NewValue)
{
element.PreviewMouseLeftButtonDown += ElementOnMouseLeftButtonDown;
}
}
private static void ElementOnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (sender is UIElement element
&& ContextMenuService.GetContextMenu(element) is ContextMenu contextMenu)
{
contextMenu.Placement = ContextMenuService.GetPlacement(element);
contextMenu.PlacementTarget = element;
contextMenu.IsOpen = true;
}
}
}
用法可能如下所示:
<Button Content="Button with ContextMenu" ContextMenuService.Placement="Bottom"
yourNS:ContextMenuTools.OpenOnLeftClick="True">
<Button.ContextMenu>
<ContextMenu x:Name="MainContextMenu">
<MenuItem Header="Do A" />
</ContextMenu>
</Button.ContextMenu>
</Button>
注意yourNS
命名空间 - 这是一个映射到附加属性类所在的 CLR 命名空间的 XAML 命名空间ContextMenuTools
,例如:
xmlns:yourNS="clr-namespace:WpfApp1"
您还可以在任何 WPF 控件实现上使用此附加属性IInputElement
,而不仅仅是在按钮上。
推荐阅读
- react-native - 当我什至不使用 TypeScript 时,为什么会收到一条错误消息,提示 Property assignment expected?
- python-3.x - AWS lambda No module named markupsafe error with jinja2
- python - How to sign a request to Amazon MWS in Python
- dc.js - 当鼠标在折线图上的任意位置时显示提示
- java - Tomcat Log is showing wrong date
- c++ - 尝试使用算术运算符防止隐式转换
- c++ - 在 Mac 上提升 python
- java - 为 Java 调试一个简单的控制台游戏
- azure - 云外壳中的 azcopy 尝试将源存储帐户内容复制到目标存储帐户失败
- postgresql - 努力手动创建与 gorm / migrate 的关系