2

Is it possible to attach context menu to a wpf control and have it opened on left-click (as opposed to more customary right-click)? I want to achieve that using xaml only (this should be a part of my control's view template).

4 Answers 4

7

Here is a way to show context menu on left-click:

Create a new left button handler on the Border element:

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

and then add this:

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

What it does, it basically maps the left-click into right-click. For reusability, you can wrap this into an attached behavior.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this is the only solution I've found that respects what you specify in the ContextMenuService.Placement... properties.
5

Here is how I would do a simple example of what I am suggesting:

The XAML:

<Window x:Class="LeftClickMenu.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow">
    <Grid>
        <Border Width="400" Height="300" Background="#ccc" BorderBrush="#333" 
                BorderThickness="1"
                MouseLeftButtonDown="Border_MouseLeftButtonDown"
                MouseRightButtonUp="Border_MouseRightButtonUp">
            <Border.ContextMenu>
                <ContextMenu x:Name="myContextMenu">
                    <MenuItem Header="Menu Item 1" />
                    <MenuItem Header="Menu Item 2" />
                    <MenuItem Header="Menu Item 3" />
                    <MenuItem Header="Menu Item 4" />
                    <MenuItem Header="Menu Item 5" />
                </ContextMenu>
            </Border.ContextMenu>
        </Border>
    </Grid>
</Window>

And the code-behind:

using System.Windows;
using System.Windows.Input;

namespace LeftClickMenu
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            myContextMenu.IsOpen = true;
        }

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

I also added the extra MouseRightButtonUp event to inhibit the right-click popup of the context menu.

2 Comments

(Sorry for late reply.) But how do I move this behaviour to style (eg. in Generic.xml). As indicated in my previous comment I get "error MC4007: The event 'MouseUp' cannot be specified on a Target tag in a Style. Use an EventSetter instead."
I agree with the error. You should use an Event setter. I don't believe there is an effective way to do that in a style since you need it to occur on a specific event.
0
  1. Create a method to programmatically open a submenu as stated in this SO article: Show menu programmatically in WPF

  2. Create an event for LeftMouseButtonDown and call that event in XAML.

4 Comments

Wouldn't doing it from code violate the separation between view and logic? To me this part belongs to view (and so should be specified in xaml).
This is the code-behind of the view which is part of the view. What you are referring to would be in regard to implementing this code in a ViewModel and I am not suggesting that at all.
Ok, so be it. But still, I do not understand the "Create an event for LeftMouseButtonDown and call that method" part. I have a style for my control inside Generic.xaml. I want the context menu to show up when I click on one of the controls defined in this style eg. Image control. So I tried to add MouseUp="method" to the Image tag, but I get: error MC4007: The event 'MouseUp' cannot be specified on a Target tag in a Style. Use an EventSetter instead. How do I wire up the event handler from within a style? Where should my method be located? Generic.xaml.cs?
I am putting a sample in a separate answer.
0

In order to open a ContextMenu in WPF with a left click, you need to ensure that the DataContext is properly bound. Here is a simple solution using a button:

<Button x:Name="myButton"
        Content="Left Click Me"
        MouseRightButtonUp="_myButton_MouseRightButtonUp"
        PreviewMouseLeftButtonDown="_myButton_MouseLeftButtonDown">
    <Button.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Item 1"/>
            <Separator/>
            <MenuItem Header="Item 2"/>
        </ContextMenu>
    </Button.ContextMenu>
</Button>

In the code behind, you need to ensure that the right click event is canceled first, then properly bind the DataContext to left click event.

/// <summary>
/// Cancels the default right-click event on a button to prevent displaying the ContextMenu
/// </summary>
private void _myButton_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
    e.Handled = true;
}

/// <summary>
/// Displays the ContextMenu of the button when the user left-clicks the mouse button
/// </summary>
private void _myButton_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    var button = sender as Button;
    if (button != null)
    {
        button.ContextMenu.DataContext = button.DataContext;
        button.ContextMenu.IsOpen = true;
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.