2

我基本上是在写一个简单的浮动面板,它的位置可以通过拖动它的标题栏(它本身就是一个网格)来改变。但我无法让它工作!它似乎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)
捕获和释放鼠标mousedownmouseup事件 - 设置网格的水平和垂直对齐方式。(这对我来说似乎很奇怪。为什么点头设置对齐会导致问题?)Mouse.Capture(gridTitle)Mouse.Capture(null)

4

1 回答 1

2

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

在两者中尝试e.GetPosition(null)(即为null而不是this_MouseLeftButtonDown_MouseMove计算正确delta的 s。

本文说明了区别: 获取相对于特定元素的鼠标位置

编辑:更强大FloatingPanel

RowDefinition在构造函数中,通过将它们放在两个单独的 s 中(并让 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;
...
于 2013-12-31T17:22:13.293 回答