这个答案与@nightcoder 的答案完全相同(感谢您的灵感!)。它使用 Blend 风格的行为,与附加属性相比,这是一种更现代的方法。
using System;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Interactivity;
/// <summary>
/// Add this to any button menu allow a left click to open the context menu as well as the right.
/// </summary>
public class ContextMenuLeftClickBehavior : Behavior<ButtonBase>
{
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.Loaded += this.OnWindowLoaded;
this.AssociatedObject.Unloaded += this.OnWindowUnloaded;
}
private void OnWindowLoaded(object sender, RoutedEventArgs e)
{
this.AssociatedObject.Click += OnMouseLeftButtonUp;
}
private void OnWindowUnloaded(object sender, RoutedEventArgs e)
{
this.AssociatedObject.Click -= OnMouseLeftButtonUp; // Cannot override OnDetached(), as this is not called on Dispose. Known issue in WPF.
}
private static void OnMouseLeftButtonUp(object sender, RoutedEventArgs e)
{
if (sender is ButtonBase fe && fe.ContextMenu != null)
{
if (fe.ContextMenu != null)
{
// If we use binding in our context menu, then it's DataContext won't be set when we show the menu on left click. It
// seems setting DataContext for ContextMenu is hardcoded in WPF when user right clicks on a control? So we have to set
// up ContextMenu.DataContext manually here.
if (fe.ContextMenu?.DataContext == null)
{
fe.ContextMenu?.SetBinding(FrameworkElement.DataContextProperty, new Binding { Source = fe.DataContext });
}
fe.ContextMenu.IsOpen = true;
}
}
}
}
然后将行为添加到按钮:
<Button>
<i:Interaction.Behaviors>
<attachedProperties:ContextMenuLeftClickBehavior/>
</i:Interaction.Behaviors>
<Button>
像 Ellipse 或 Rectangle 这样的元素没有OnClick
事件,这意味着没有什么能真正适用于任何交互的东西。因此,将所有内容包装在一个按钮中以获取该OnClick
事件。也可以通过将鼠标光标更改为鼠标悬停时的手来暗示该区域是可点击的。
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Ellipse Fill="{TemplateBinding Background}" Width="16" Height="16"/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<!-- Bind to custom color in ViewModel -->
<Setter Property="Background" Value="{Binding CustomBrush}"/>
<Setter Property="Cursor" Value="Hand"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>