8

WPF の既定の動作はContextMenu、ユーザーが右クリックしたときに表示することです。ContextMenuユーザーが左クリックしたときに表示したい。これは の単純なプロパティであるように見えますがContextMenu、そうではありません。

コード ビハインドでイベントを処理しLeftMouseButtonDown、コンテキスト メニューを表示するように調整しました。

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

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

4

5 に答える 5

13

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() メソッド内のコメントに注意してください)

于 2015-03-18T13:53:35.337 に答える
9

私が提案するのは、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

于 2009-02-18T23:37:06.483 に答える
4

Caleb の答えは正しいですが、実際のコードは含まれていません。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
于 2014-03-26T15:57:32.230 に答える
-1

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

それが何をするか、それは基本的に左クリックを右クリックにマップします。再利用性のために、これをアタッチされた動作にラップできます。

于 2014-12-29T18:44:35.003 に答える