【问题标题】:Wrong mouse position in drag and drop inside grid class在网格类中拖放鼠标位置错误
【发布时间】:2023-03-13 08:01:01
【问题描述】:

我基本上是在编写一个简单的浮动面板,它的位置可以通过拖动其标题栏(它本身就是一个网格)来更改。但我无法让它工作! MouseEventArgs.GetPosition 似乎返回了错误的点。我在这里想念什么?

public class FloatingPanel : Grid
    {
        Grid gridTitle;

        bool dragging = false;
        Point lastPos;

        public FloatingPanel(UserControl gadget)
        {
            this.MouseMove += FloatingPanel_MouseMove;

            gridTitle = new Grid();
            gridTitle.Height = 25;
            gridTitle.VerticalAlignment = System.Windows.VerticalAlignment.Top;
            gridTitle.Background = Brushes.Cyan;
            gridTitle.MouseLeftButtonDown += gridTitle_MouseLeftButtonDown;
            gridTitle.MouseLeftButtonUp += gridTitle_MouseLeftButtonUp;
            this.Children.Add(gridTitle);

            this.Height = gadget.Height + 25;
            this.Width = gadget.Width;

            gadget.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
            this.Children.Add(gadget);
        }

        void gridTitle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            dragging = false;
        }

        void gridTitle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            lastPos = Mouse.GetPosition(this);
            dragging = true;
        }

        void FloatingPanel_MouseMove(object sender, MouseEventArgs e)
        {
            if(dragging)
            {
                Vector delta = e.GetPosition(this) - lastPos;
                this.Margin = new Thickness(this.Margin.Left + delta.X, this.Margin.Top + delta.Y, this.Margin.Right, this.Margin.Bottom);
                lastPos = e.GetPosition(this);
            }
        }
    }  

我也尝试过使用System.Windows.Forms.Cursor.PositionSystem.Windows.Forms.Control.MousePosition 来给出屏幕上的位置。但是没有运气。
解决方案:通过 3 次修改解决了这个问题(正如 Sphinxxx 指出的那样):
- 使用MouseEventArgs.GetPosition(null) 代替MouseEventArgs.GetPosition(this)
- 使用Mouse.Capture(gridTitle)Mouse.Capture(null)mousedownmouseup 事件中捕获和释放鼠标
- 设置网格的水平和垂直对齐方式。 (这对我来说似乎很奇怪。为什么 nod 设置对齐会导致问题?)

【问题讨论】:

    标签: c# wpf .net-4.0 mousemove mouse-position


    【解决方案1】:

    _MouseMove 中,您尝试使用e.GetPosition(this) 计算移动,但这只会获取鼠标指针位置相对于您的Grid。您需要找到相对于其他一些 UI 元素的位置,例如包含Window 以便知道网格应该移动多少。

    _MouseLeftButtonDown_MouseMove 中尝试e.GetPosition(null)(即null 而不是this)来计算正确的deltas。

    这篇文章说明了不同之处: Getting the Mouse Position Relative to a Specific Element

    编辑:更强大的FloatingPanel

    在构造函数中,通过将小工具放在两个单独的RowDefinitions 中(并让 WPF 处理宽度和高度),避免小工具最终位于标题栏顶部:

    public FloatingPanel(FrameworkElement gadget)
    {
        gridTitle = new Grid();
        gridTitle.Height = 25;
        gridTitle.Background = Brushes.Cyan;
    
        gridTitle.MouseLeftButtonDown += gridTitle_MouseLeftButtonDown;
        gridTitle.MouseMove += gridTitle_MouseMove;
        gridTitle.MouseLeftButtonUp += gridTitle_MouseLeftButtonUp;
    
        //Create two grid rows - one to hold the title bar..
        this.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
        Grid.SetRow(gridTitle, 0);
        this.Children.Add(gridTitle);
    
        //..and one two hold the gadget:
        this.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
        Grid.SetRow(gadget, 1);
        this.Children.Add(gadget);
    }
    

    ..ButtonDown/..ButtonUp 处理程序中,使标题栏“捕捉”(并释放)鼠标移动,这样鼠标指针在移动过快时就不会“滑落”:

    void gridTitle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        //Relese a previous capture:
        Mouse.Capture(null);
        dragging = false;
    }
    
    void gridTitle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        lastPos = Mouse.GetPosition(null);
    
        //Capture the mouse to ensure we get all future mouse movements:
        Mouse.Capture(gridTitle);
        dragging = true;
    }
    

    编辑 2: 没有Mouse.Capture() 的替代方案:

    ...
    gridTitle.MouseLeftButtonDown += gridTitle_MouseLeftButtonDown;
    
    //gridTitle.MouseMove += gridTitle_MouseMove;
    
    //The parent Window isn't available yet here in the constructor,
    //so we must wait for our Loaded event to hook it up:
    this.Loaded += (s, e) => { Window.GetWindow(this).MouseMove += gridTitle_MouseMove; };
    
    gridTitle.MouseLeftButtonUp += gridTitle_MouseLeftButtonUp;
    ...
    

    【讨论】:

    • 不幸的是,这并没有解决问题。我也尝试过使用System.Windows.Forms.Cursor.PositionSystem.Windows.Forms.Control.MousePosition,它们给出了屏幕上的位置。但没有运气。
    • 这里工作正常。您是否将所有三个呼叫都更改为.GetPosition()?究竟是什么不工作?您的网格是否完全不移动,只是偶尔移动,还是移动方式错误?
    • 它移动得很慢!这是我在 MainWindow 的构造函数中使用它的方式: UserControl1 c = new UserControl1();浮动面板 p = 新的浮动面板(c); layoutRoot.Children.Add(p); (layoutRoot 是 MainWindow 的内容网格)
    • 好的,那个可以修。 FloatingPanelGrid,默认情况下,Grid 拉伸(水平和垂直)。在FloatingPanel的构造函数中添加这两行:this.HorizontalAlignment = HorizontalAlignment.Left; this.VerticalAlignment = VerticalAlignment.Top;
    • 好吧,也许您可​​以收听整个MouseMoves Window 而不仅仅是gridTitle?我会更新答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-12
    • 1970-01-01
    相关资源
    最近更新 更多