简体   繁体   中英

ContextMenu position is unpredictable when I'm trying to show same instance of menu more than once

I need to show ContextMenu at specific location and it works just fine the first time. If I move mouse cursor and try to show the same ContextMenu , then it may show up at different location, even if HorizontalOffset and VerticalOffset is hardcoded.

How can I open ContextMenu at specific location without reinitializing it each time?

System.Windows.Controls.Input.Toolkit version: 5.0.5.0

XAML

<Grid x:Name="LayoutRoot" Background="White"
      MouseRightButtonUp="LayoutRoot_MouseRightButtonUp"
      MouseRightButtonDown="LayoutRoot_MouseRightButtonDown"/>

Code

private ContextMenu menu;

private void LayoutRoot_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
    if (menu == null)
    {
        menu = new ContextMenu();
        menu.Items.Add("test");
    }

    menu.HorizontalOffset = 100;
    menu.VerticalOffset = 100;

    menu.IsOpen = true;
}

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

There appears to be a bug in the ContextMenu. It's not picking up the mouse pointer position on the first click.

Here's a workaround:

private void LayoutRoot_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
    if (menu == null)
    {
        menu = new ContextMenu();
        menu.Items.Add("test");
        menu.HorizontalOffset = 100;
        menu.VerticalOffset = 100;
    }
    else
    {
        menu.HorizontalOffset = 100 - e.GetPosition(null).X;
        menu.VerticalOffset = 100 - e.GetPosition(null).Y;                
    }

    menu.IsOpen = true;
}

I had a closer look at the disassembled sources, and it appears that once a ContextMenu is shown, MouseTracking is enabled, which is why we need to adjust the offset to cancel out the effect of ContextMenu trying to adjust it's position based on the last mousemove event, not the last MouseRightButtonUp position. Here's a revised code sample to account for it:

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();

        LayoutRoot.MouseRightButtonDown += LayoutRoot_MouseRightButtonDown;
        LayoutRoot.MouseRightButtonUp += LayoutRoot_MouseRightButtonUp;
        LayoutRoot.MouseMove += LayoutRoot_MouseMove;
        SetupContextMenu();
    }

    private void SetupContextMenu()
    {
        if (menu == null)
        {
            menu = new ContextMenu();
            menu.Items.Add("test");
            ContextMenuService.SetContextMenu(this, menu);
        }

    }

    private ContextMenu menu;

    private void LayoutRoot_MouseMove(object sender, MouseEventArgs e)
    {
        var mousePosition = e.GetPosition(this);
        menu.HorizontalOffset = 100 - mousePosition.X;
        menu.VerticalOffset = 100 - mousePosition.Y;
    }

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM