WPF C#如何使用鼠标拖动控件

时间:2019-04-21 23:57:19

标签: c# wpf canvas draggable drag

我正在尝试制作一个在画布上拖动的UserControl。我正在使用C#和WPF。我在网上看到了很多例子,但我只需要最低限度的内容。

我找到了一篇文章:“ WPF中的可拖动控件”

有人回应:

如果您想手动操作,请使用以下算法:

在发生MouseDown事件时:保存鼠标位置,控件的TopLeft位置以及这些坐标的delta(offset),并设置一些布尔字段标志,例如。 IsDragStartted为true。 在MouseMove上,检查拖动是否开始,并使用“鼠标位置和偏移量”来计算控件的TopLeft位置的新值

在MouseUp事件上,将IsDragStarted设置为false


我在应用此程序时遇到麻烦。

公共局部类UserControl1:UserControl     {

    private Point startingMousePosition;
    private Point endingMousePosition;
    private Point startingControlPosition;
    bool isDragStarted;

    public UserControl1()
    {
        InitializeComponent();

    }

    private void Grid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if(!isDragStarted)
        {
            startingControlPosition.X = Canvas.GetLeft(this);
            startingControlPosition.Y = Canvas.GetTop(this);

            startingMousePosition.X = e.GetPosition(this.Parent as Canvas).X;
            startingMousePosition.Y = e.GetPosition(this.Parent as Canvas).Y;
        }



    }

    private void Grid_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            isDragStarted = true;

            if (isDragStarted)
            {

                endingMousePosition.X = e.GetPosition(this.Parent as Canvas).X;
                endingMousePosition.Y = e.GetPosition(this.Parent as Canvas).Y;

                Canvas.SetLeft(this, endingMousePosition.X - startingControlPosition.X);
                Canvas.SetTop(this, endingMousePosition.Y - startingControlPosition.Y);

            }
        }

    }



    private void Grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {

        isDragStarted = false;
    }



}

这是我的主窗口WPF表单的代码:

{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{

    UserControl1 userCTL;
    public MainWindow()
    {
        InitializeComponent();

        userCTL = new UserControl1();
        userCTL.Width = 50;
        userCTL.Height = 100;
        Canvas.SetTop(userCTL,20);
        Canvas.SetLeft(userCTL, 20);

        CanvasMain.Children.Add(userCTL);

    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        AdornerLayer myAdornerLayer = AdornerLayer.GetAdornerLayer(userCTL);
        if (myAdornerLayer != null)
        {
            myAdornerLayer.Add(new SimpleCircleAdorner(userCTL));
        } 
    }




}

}

这是我在主窗口中的WPF代码:

<Window x:Class="WpfApplicationEvent.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="374.306" Width="594.271" Loaded="Window_Loaded">
<Grid>
    <ScrollViewer Margin="46,23,74,33" PanningMode="Both" HorizontalScrollBarVisibility="Visible">
        <Canvas x:Name="CanvasMain" Height="395" Width="506">

        </Canvas>
    </ScrollViewer>

</Grid>
</Window>

我还尝试放置装饰物,以便最终调整控件的大小。装饰没有了,但是他们什么也没做。

我在创建的UserControl1中拥有所有拖动控件,然后将其拖动,但是当我再次单击UserControl1实例再次拖动它时,它将重置为SetTop(0)和SetLeft(0)位置。它怪异地跳到那里!我期望将UserControl1实例拖到光标所在的位置。会在第一次尝试时执行它,但是随后我单击UserControl1再次将其拖动一次,它会跳到(0,0)或接近它。

1 个答案:

答案 0 :(得分:0)

您在这里遇到了一些问题...

  1. 应该将PreviewMouseDown事件处理程序添加到子控件中,否则您将不知道要拖动哪个对象。
  2. 您将要在父级Canvas上拖动,所以要在其中添加MouseMove处理程序。
  3. 再次在Canvas控件上调用CaptureMouse(),并使其在拖动过程中保持捕获状态。
  4. 计算鼠标相对于要拖动的控件的左上角的位置,然后在每次设置位置时反向应用该偏移量。这将使您在拖动过程中在鼠标光标下单击的点保持不变,并使其停止“跳到”新位置,这对用户很烦人。

因此您的画布XAML现在应如下所示:

<Canvas x:Name="CanvasMain" Height="395" Width="506"
    PreviewMouseMove="CanvasMain_PreviewMouseMove"
    PreviewMouseUp="CanvasMain_PreviewMouseUp" />

您的后台代码应如下所示:

public MainWindow()
{
    InitializeComponent();

    var userCTL = new UserControl();    // <-- replace with your own control
    userCTL.Background = Brushes.Blue;  // <-- added this so I can see it
    userCTL.Width = 50;
    userCTL.Height = 100;
    Canvas.SetTop(userCTL, 20);
    Canvas.SetLeft(userCTL, 20);
    userCTL.PreviewMouseDown += UserCTL_PreviewMouseDown;

    CanvasMain.Children.Add(userCTL);
}

UIElement dragObject = null;
Point offset;

private void UserCTL_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    this.dragObject = sender as UIElement;
    this.offset = e.GetPosition(this.CanvasMain);
    this.offset.Y -= Canvas.GetTop(this.dragObject);
    this.offset.X -= Canvas.GetLeft(this.dragObject);
    this.CanvasMain.CaptureMouse();
}

private void CanvasMain_PreviewMouseMove(object sender, MouseEventArgs e)
{
    if (this.dragObject == null)
        return;
    var position = e.GetPosition(sender as IInputElement);
    Canvas.SetTop(this.dragObject, position.Y - this.offset.Y);
    Canvas.SetLeft(this.dragObject, position.X - this.offset.X);
}

private void CanvasMain_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
    this.dragObject = null;
    this.CanvasMain.ReleaseMouseCapture();
}

您可能还希望向“画布”添加MouseLeave处理程序,以阻止用户将控件拖到可见客户区域之外。