2009-02-17 100 views
6

WPF ContextMenu的默認行爲是在用戶右鍵單擊時顯示它。我希望ContextMenu在用戶左鍵單擊時顯示。看起來這應該是ContextMenu上的一個簡單屬性,但事實並非如此。左鍵單擊僅使用XAML顯示ContextMenu

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

我在我的項目中使用MVVM,這意味着我使用DataTemplate s作爲具有上下文菜單的項目。要擺脫代碼隱藏並找到一種方法來顯示使用XAML中的觸發器或屬性的上下文菜單將更加優雅。

此問題的任何想法或解決方案?

+0

這是一個偏離Windows的標準,你是否有很好的理由這樣做? – 2009-02-17 08:43:36

+0

這是一個好點,也許我應該ld正在使用ContextMenu以外的其他功能來完成此操作。它基本上是一個下拉式菜單,當你點擊該項目時,不是按鈕,而是一種緊張的方式。ContextMenu似乎是一個明顯的選擇,但也許這是錯誤的。 – timothymcgrath 2009-02-20 03:39:51

+0

看到我在這裏使用Expression Blend觸發器的答案:http://stackoverflow.com/a/4917707/87912 – 2012-08-21 04:57:13

回答

8

我會建議做的是製作一個新的靜態類與附加的DependencyProperty。調用LeftClickContextMenu類和Enabled屬性(只是想法)。當您註冊DependencyProperty時添加一個更改回調。然後在屬性改變回調,如果Enabled設置爲true,然後添加一個處理程序到LeftMouseButtonDown事件,並在那裏做你的東西。如果Enabled設置爲false,則刪除處理程序。這可以讓你在你的xaml中簡單地使用下面的內容來將它設置爲任何屬性。

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

這種技術被稱爲附加的行爲,你可以將此代碼項目的文章中閱讀更多關於它:http://www.codeproject.com/KB/WPF/AttachedBehaviors.aspx

3

雖然迦勒的答案是正確的,它不包括工作代碼。我安裝了一個使用VB.NET的例子(對不起),所以我在這裏發佈它。

<Window x:Class="MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:AttachedBehaviorTest.AttachedBehaviorTest" 
    Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <StackPanel> 
      <TextBlock local:ContextMenuLeftClickBehavior.IsLeftClickEnabled="True">Some Text Goes Here 
       <TextBlock.ContextMenu> 
        <ContextMenu> 
         <MenuItem Header="Test1" /> 
        </ContextMenu> 
       </TextBlock.ContextMenu>    
      </TextBlock> 

     </StackPanel> 
    </Grid> 
</Window> 
Namespace AttachedBehaviorTest 

    Public NotInheritable Class ContextMenuLeftClickBehavior 

     Private Sub New() 
     End Sub 

     Public Shared Function GetIsLeftClickEnabled(obj As DependencyObject) As Boolean 
      Return CBool(obj.GetValue(IsLeftClickEnabled)) 
     End Function 

     Public Shared Sub SetIsLeftClickEnabled(obj As DependencyObject, value As Boolean) 
      obj.SetValue(IsLeftClickEnabled, value) 
     End Sub 

     Public Shared ReadOnly IsLeftClickEnabled As DependencyProperty = _ 
      DependencyProperty.RegisterAttached("IsLeftClickEnabled", GetType(Boolean), GetType(ContextMenuLeftClickBehavior), New UIPropertyMetadata(False, AddressOf OnIsLeftClickEnabled)) 

     Private Shared Sub OnIsLeftClickEnabled(sender As Object, e As DependencyPropertyChangedEventArgs) 
      Dim fe As FrameworkElement = TryCast(sender, FrameworkElement) 
      If fe IsNot Nothing Then 
       Dim IsEnabled As Boolean = CBool(e.NewValue) 
       If IsEnabled = True Then 
        AddHandler fe.MouseLeftButtonUp, AddressOf OnMouseLeftButtonUp 
        Debug.Print("Added Handlers") 
       Else 
        RemoveHandler fe.MouseLeftButtonUp, AddressOf OnMouseLeftButtonUp 
        Debug.Print("RemovedHandlers") 
       End If 
      End If 
     End Sub 

     Private Shared Sub OnMouseLeftButtonUp(sender As Object, e As RoutedEventArgs) 
      Debug.Print("OnMouseLeftButtonUp") 
      Dim fe As FrameworkElement = TryCast(sender, FrameworkElement) 
      If fe IsNot Nothing Then 
       'Next Line is Needed if Context Menu items are Data Bound 
       'fe.ContextMenu.DataContext = fe.DataContext 
       fe.ContextMenu.IsOpen = True 
      End If 
     End Sub 

    End Class 

End Namespace 
-2

忘記 「只有XAML」 的東西。這可以很好地解決,當你把它包裝到附加的行爲。

這裏是顯示在左側單擊上下文菜單的方式:

Border元素上創建一個新的左按鈕處理程序:

<Border x:Name="Win" 
     Width="40" 
     Height="40" 
     Background="Purple" 
     MouseLeftButtonUp="UIElement_OnMouseLeftButtonUp"> 

再補充一點:

private void UIElement_OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e) 
{ 
    e.Handled = true; 

    var mouseDownEvent = 
     new MouseButtonEventArgs(Mouse.PrimaryDevice, 
      Environment.TickCount, 
      MouseButton.Right) 
     { 
      RoutedEvent = Mouse.MouseUpEvent, 
      Source = Win, 
     }; 


    InputManager.Current.ProcessInput(mouseDownEvent); 
} 

它的功能,它基本上將左鍵單擊到右鍵單擊。爲了可重用性,您可以將其包裝爲附加行爲。

3

我剛編寫和測試此基礎上HK1的回答(你也可以在Attached Properties Overview)閱讀附加屬性:

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()方法)

相關問題