Dot-Net

僅使用 XAML 在左鍵點擊時顯示 ContextMenu

  • March 4, 2019

WPF 的預設行為ContextMenu是在使用者右鍵點擊時顯示它。我希望在ContextMenu使用者左鍵點擊時顯示。看起來這應該是 上的一個簡單屬性ContextMenu,但事實並非如此。

我操縱它,以便我LeftMouseButtonDown在程式碼隱藏中處理事件,然後顯示上下文菜單。

我在我的項目中使用 MVVM,這意味著我將DataTemplates 用於具有上下文菜單的項目。擺脫程式碼隱藏並找到一種使用 XAML 中的觸發器或屬性來顯示上下文菜單的方法會更加優雅。

對此問題有任何想法或解決方案嗎?

我建議做的是製作一個帶有附加 DependencyProperty 的新靜態類。呼叫類 LeftClickContextMenu 和屬性 Enabled(只是想法)。當您註冊 DependencyProperty 時,添加一個 on changed 回調。然後在屬性更改回調中,如果 Enabled 設置為 true,然後將處理程序添加到 LeftMouseButtonDown 事件並在那裡執行您的操作。如果 Enabled 設置為 false,則刪除處理程序。這允許您通過簡單地在 xaml 中使用以下內容將其設置為任何屬性。

<Border namespace:LeftClickContextMenu.Enabled="True" />

這種技術稱為附加行為,您可以在此程式碼項目文章中了解更多資訊:http: //www.codeproject.com/KB/WPF/AttachedBehaviors.aspx

我剛剛根據 HK1 的回答編寫並測試了這個(您還可以閱讀附加屬性概述中的附加屬性)

public static class ContextMenuLeftClickBehavior
{
   public static bool GetIsLeftClickEnabled(DependencyObject obj)
   {
       return (bool)obj.GetValue(IsLeftClickEnabledProperty);
   }

   public static void SetIsLeftClickEnabled(DependencyObject obj, bool value)
   {
       obj.SetValue(IsLeftClickEnabledProperty, value);
   }

   public static readonly DependencyProperty IsLeftClickEnabledProperty = DependencyProperty.RegisterAttached(
       "IsLeftClickEnabled", 
       typeof(bool), 
       typeof(ContextMenuLeftClickBehavior), 
       new UIPropertyMetadata(false, OnIsLeftClickEnabledChanged));

   private static void OnIsLeftClickEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
   {
       var uiElement = sender as UIElement;

       if(uiElement != null) 
       {
           bool IsEnabled = e.NewValue is bool && (bool) e.NewValue;

           if(IsEnabled)
           {
               if(uiElement is ButtonBase)
                   ((ButtonBase)uiElement).Click += OnMouseLeftButtonUp;
               else
                   uiElement.MouseLeftButtonUp += OnMouseLeftButtonUp;
           }
           else
           {
               if(uiElement is ButtonBase)
                   ((ButtonBase)uiElement).Click -= OnMouseLeftButtonUp;
               else
                   uiElement.MouseLeftButtonUp -= OnMouseLeftButtonUp;
           }
       }
   }

   private static void OnMouseLeftButtonUp(object sender, RoutedEventArgs e)
   {
       Debug.Print("OnMouseLeftButtonUp");
       var fe = sender as FrameworkElement;
       if(fe != 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, although I'm not sure)
           // 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 Content="Do All" local:ContextMenuLeftClickBehavior.IsLeftClickEnabled="True" >
   <Button.ContextMenu>
       <ContextMenu>
           <MenuItem Header="Make everything awesome" />
           <MenuItem Header="Control the World" />
       </ContextMenu>
   </Button.ContextMenu>
</Button>

(注意 OnMouseLeftButtonUp() 方法中的註釋)

引用自:https://stackoverflow.com/questions/555252