7


2

XAMLのみを使用して左クリックでコンテキストメニューを表示

WPFの `ContextMenu`のデフォルトの振る舞いは、ユーザーが右クリックしたときにそれを表示することです。 ユーザが左クリックしたときに `ContextMenu`が表示されるようにします。 これは `ContextMenu`の単純なプロパティであるべきだと思われますが、そうではありません。

コードビハインドで `LeftMouseButtonDown`イベントを処理してからコンテキストメニューを表示するように、それをリグしました。

私は自分のプロジェクトでMVVMを使用しています。つまりコンテキストメニューを持つアイテムには `DataTemplate`を使用しています。 コードビハインドを取り除き、XAMLのトリガーまたはプロパティを使用してコンテキストメニューを表示する方法を見つける方がはるかにエレガントです。

この問題に対するアイデアや解決策はありますか?

4 Answer


9


私がやることを提案するのは、DependencyPropertyを添付した新しい静的クラスを作ることです。 クラスLeftClickContextMenuとプロパティEnabled(単なるアイデア)を呼び出します。 DependencyPropertyを登録するときに、変更後のコールバックを追加します。 次に、Enabledプロパティがtrueに設定されている場合、プロパティの変更されたコールバックで、LeftMouseButtonDownイベントにハンドラを追加して、そこで処理を行います。 Enabledがfalseに設定されている場合は、ハンドラを削除します。 これはあなたのxamlで単に以下を使うことによってあなたが何かのプロパティのようにそれを設定することを可能にするでしょう。


この手法は、添付の動作と呼ばれ、このコードプロジェクトの記事で詳細を読むことができます。http://www.codeproject.com/KB/WPF/AttachedBehaviors.aspx


7


私はちょうどHK1の答えに基づいてこれを書いてテストしました(あなたは Attachedで添付プロパティについても読むことができますプロパティ概要)

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); }

パブリック静的読み取り専用DependencyProperty IsLeftClickEnabledProperty = DependencyProperty.RegisterAttached( "IsLeftClickEnabled"、typeof(ブール値)、typeof(ContextMenuLeftClickBehavior)、new UIPropertyMetadata(false、OnIsLeftClickEnable);

OnIsLeftClickEnabledChanged(オブジェクト送信側、DependencyPropertyChangedEventArgs e){var uiElement = UIElementとしての送信側。

if(uiElement!= null){bool IsEnabled = e.NewValueはブール値です。

if(IsEnabled){if(uiElementはButtonBase)((ButtonBase)uiElement).Click = OnMouseLeftButtonUp;それ以外の場合はuiElement.MouseLeftButtonUp = OnMouseLeftButtonUp; } else {if(uiElementはButtonBase)((ButtonBase)uiElement).Click  -  = OnMouseLeftButtonUp;そうでなければuiElement.MouseLeftButtonUp  -  = OnMouseLeftButtonUp; }}}

OnMouseLeftButtonUp(オブジェクト送信側、RoutedEventArgs e){Debug.Print( "OnMouseLeftButtonUp"); var fe = FrameworkElementとしての送信者。 if(fe!= null){//コンテキストメニューでバインディングを使用している場合、左クリックでメニューを表示してもDataContextは設定されません//(ContextMenuのDataContextの設定はWPFでハードコードされているようです)よくわかりませんが、コントロールを右クリックしてください。//ここでは、ContextMenu.DataContextを手動で設定する必要があります。 {Source = fe.DataContext}); }

fe.ContextMenu.IsOpen = true; }}

}

…​


(OnMouseLeftButtonUp()メソッド内のコメントに注意してください)


4


Calebの答えは正しいのですが、実用的なコードは含まれていません。 VB.NETを使用して例を設定しました(申し訳ありません)ので、ここに投稿します。

            Some Text Goes Here
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


-1


「唯一のxaml」を忘れてください。 これを添付の動作にまとめると、うまく解決できます。

左クリックでコンテキストメニューを表示する方法は次のとおりです。

`+ Border +`要素に新しい左ボタンハンドラーを作成します。


そしてこれを追加します。

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);
}

それがすること、それは基本的に左クリックを右クリックにマッピングします。 再利用可能にするために、これを添付の動作にラップすることができます。