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

问题描述 投票:0回答:1

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

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

有人回复:

如果您想手动使用以下算法:

在MouseDown事件中:保存鼠标位置,TopLeft控制位置和这些坐标的delta(偏移),并设置一些布尔字段标志,例如。 IsDragStartted为true。在MouseMove上检查拖动是否已启动并使用鼠标位置和偏移量来计算TopLeft控件位置的新值

在MouseUp事件上将IsDragStarted设置为false


我无法应用此功能。

public partial class 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)或接近它。

c# wpf canvas draggable drag
1个回答
0
投票

你在这里遇到了几个问题......

  1. 应将PreviewMouseDown事件处理程序添加到子控件中,否则您将无法知道要拖动的对象。
  2. 您将要拖过父Canvas,因此将MouseMove处理程序添加到该Canvas中。
  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();
}

您可能还希望向Canvas添加MouseLeave处理程序以停止用户在可见客户区域外拖动控件。

© www.soinside.com 2019 - 2024. All rights reserved.