C# WPF 鼠标点击事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/48348259/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 14:09:31  来源:igfitidea点击:

C# WPF mouse click event

c#wpfeventsbuttonclick

提问by Doua Ali

I'm using C# with WPF. I have a grid of buttons and I need to do the following: If the user presses one button, moves the cursor and releases it on another button, the content of the first button is moved to the other one, something like dragging.

我在 WPF 中使用 C#。我有一个按钮网格,我需要执行以下操作:如果用户按下一个按钮,移动光标并在另一个按钮上释放它,第一个按钮的内容将移动到另一个按钮,类似于拖动。

I tried using The previewmousedown and the previewmouseup button events to know which button the mouse is pressed on and which button it is released on but the previewmouseup event is fired also on the button the mouse is pressed on (not on the one the mouse is released on).

我尝试使用 previewmousedown 和 previewmouseup 按钮事件来了解按下鼠标的哪个按钮以及释放鼠标的按钮,但也会在按下鼠标的按钮上触发 previewmouseup 事件(而不是在释放鼠标的那个按钮上)在)。

Any ideas about how to implement this in other ways, please? Thanks a lot in advance.

关于如何以其他方式实现这一点的任何想法,好吗?非常感谢。

回答by Mike Strobel

The easiest way to do drag & drop is with the built-in DragDropAPI. Here's a proof of concept for you, where buttons can be clicked normally *and*dragged to swap their content.

进行拖放的最简单方法是使用内置DragDropAPI。这是为您提供的概念证明,可以正常单击按钮*和*拖动按钮以交换其内容。

If you want to change the behavior so the content is copied or moved (instead of swapped), just change the lines under the comment in OnButtonDrop.

如果您想更改行为以便复制或移动内容(而不是交换),只需更改OnButtonDrop.

ButtonDragging.xaml:

ButtonDragging.xaml:

<Window x:Class="WpfTest2.ButtonDragging"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <DockPanel LastChildFill="True">
    <Label x:Name="_statusLabel" DockPanel.Dock="Bottom" Content=" " />
    <Grid x:Name="_grid" />
  </DockPanel>
</Window>

ButtonDragging.xaml.cs:

ButtonDragging.xaml.cs:

public partial class ButtonDragging
{
    private Button _mouseDownButton;
    private Point _mouseDownLocation;

    public ButtonDragging()
    {
        InitializeComponent();
        BuildButtonGrid();
    }

    private void BuildButtonGrid()
    {
        const int rows = 5;
        const int columns = 5;

        var starLength = new GridLength(1d, GridUnitType.Star);

        for (var i = 0; i < rows; i++)
            _grid.RowDefinitions.Add(new RowDefinition { Height = starLength });

        for (var i = 0; i < columns; i++)
            _grid.ColumnDefinitions.Add(new ColumnDefinition { Width = starLength });

        for (var i = 0; i < rows; i++)
        {
            for (var j = 0; j < columns; j++)
            {
                var button = new Button { Content = $@"({i}, {j})", AllowDrop = true };

                Grid.SetColumn(button, i);
                Grid.SetRow(button, j);

                button.PreviewMouseMove += OnButtonMouseMove;
                button.PreviewMouseLeftButtonDown += OnButtonLeftButtonDown;
                button.PreviewMouseLeftButtonUp += OnButtonLeftButtonUp;
                button.Drop += OnButtonDrop;
                button.Click += OnButtonClick;
                button.LostMouseCapture += OnButtonLostMouseCapture;

                _grid.Children.Add(button);
            }
        }
    }

    private void OnButtonClick(object sender, RoutedEventArgs e)
    {
        _statusLabel.Content = $@"You clicked {(sender as Button)?.Content}!";
    }

    private void ClearPendingDrag()
    {
        _mouseDownButton = null;
        _mouseDownLocation = default(Point);
    }

    private void OnButtonDrop(object sender, DragEventArgs e)
    {
        ClearPendingDrag();

        var source = e.Data.GetData(typeof(object)) as Button;
        if (source == null)
            return;

        var target = (Button)sender;
        if (target == source)
            return;

        var sourceContent = source.Content;
        var targetContent = target.Content;

        // As a proof of concept, this swaps the content of the source and target.
        // Change as necessary to get the behavior you want.

        target.Content = sourceContent;
        source.Content = targetContent;

        _statusLabel.Content = $@"You swapped {sourceContent} with {targetContent}!";
    }

    private void OnButtonLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        var button = (Button)sender;

        _mouseDownButton = button;
        _mouseDownLocation = e.GetPosition(button);

        if (!Mouse.Capture(button, CaptureMode.SubTree))
            ClearPendingDrag();
    }

    private void OnButtonLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        ClearPendingDrag();
    }

    private void OnButtonMouseMove(object sender, MouseEventArgs e)
    {
        if (_mouseDownButton == null)
            return;

        var position = e.GetPosition(_mouseDownButton);
        var distance = position - _mouseDownLocation;

        if (Math.Abs(distance.X) > SystemParameters.MinimumHorizontalDragDistance ||
            Math.Abs(distance.Y) > SystemParameters.MinimumVerticalDragDistance)
        {
            var button = (Button)sender;
            var data = new DataObject(typeof(object), button);

            data.SetData("Source", sender);

            DragDrop.DoDragDrop(button, data, DragDropEffects.Move);

            ClearPendingDrag();
        }
    }

    private void OnButtonLostMouseCapture(object sender, MouseEventArgs e)
    {
        ClearPendingDrag();
    }
}

Note that there are probably some third-party (and open source) drag and drop solutions out there that are more MVVM-friendly. It's worth checking out, but this should get you a minimum viable deliverable.

请注意,可能有一些第三方(和开源)拖放解决方案对 MVVM 更友好。值得一试,但这应该可以为您提供最小可行的可交付成果。

回答by Lion King

Take a look at this blog post. This is the best drag and drop article I read online.

看看这篇博文。这是我在网上阅读的最好的拖放文章。

From the link below here are the series of events for a drag and drop operation:

从下面的链接这里是拖放操作的一系列事件:

  1. Dragging is initiated by calling the DoDragDropmethod for the source control. The DoDragDropmethod takes two parameters:

    data, specifying the data to pass

    allowedEffects, specifying which operations (copying and/or moving) are allowed A new DataObjectobject is automatically created.

  2. This in turn raises the GiveFeedbackevent. In most cases you do not need to worry about the GiveFeedbackevent, but if you wanted to display a custom mouse pointer during the drag, this is where you would add your code.

  3. Any control with its AllowDropproperty set to Trueis a potential drop target. The AllowDropproperty can be set in the Properties window at design time, or programmatically in the Form_Loadevent.

  4. As the mouse passes over each control, the DragEnterevent for that control is raised. The GetDataPresentmethod is used to make sure that the format of the data is appropriate to the target control, and the Effect property is used to display the appropriate mouse pointer.

  5. If the user releases the mouse button over a valid drop target, the DragDropevent is raised. Code in the DragDropevent handler extracts the data from the DataObjectobject and displays it in the target control.

  1. 拖动是通过调用DoDragDrop源控件的方法启动的。该DoDragDrop方法有两个参数:

    data, 指定要传递的数据

    allowedEffects, 指定允许哪些操作(复制和/或移动)DataObject自动创建新对象。

  2. 这反过来又引发了GiveFeedback事件。在大多数情况下,您无需担心该GiveFeedback事件,但如果您想在拖动过程中显示自定义鼠标指针,您可以在此处添加代码。

  3. 任何AllowDrop属性设置为 的控件True都是潜在的放置目标。该AllowDrop属性可以在设计时在“属性”窗口中设置,也可以在Form_Load事件中以编程方式设置。

  4. 当鼠标经过每个控件时,DragEnter会引发该控件的事件。该GetDataPresent方法用于确保数据格式适合目标控件,Effect 属性用于显示合适的鼠标指针。

  5. 如果用户在有效的放置目标上释放鼠标按钮,DragDrop则会引发该事件。DragDrop事件处理程序中的代码从DataObject对象中提取数据并将其显示在目标控件中。

To detect a mouse Drag operation on the source, source control needs to subscribe to MouseLeftButtonDownand MouseMove.

要检测源上的鼠标拖动操作,源代码管理需要订阅MouseLeftButtonDownMouseMove

void Window1_Loaded(object sender, RoutedEventArgs e)
     {
         this.DragSource.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(DragSource_PreviewMouseLeftButtonDown);
         this.DragSource.PreviewMouseMove += new MouseEventHandler(DragSource_PreviewMouseMove);
     }

To prevent from starting a false drag & drop operation where the user accidentally drags, you can use SystemParameters.MinimumHorizontalDragDistanceand SystemParameters.MinimumVerticalDragDistance.

为防止在用户意外拖动的情况下启动错误的拖放操作,您可以使用SystemParameters.MinimumHorizontalDragDistanceSystemParameters.MinimumVerticalDragDistance

void DragSource_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed && !IsDragging)
            {
                Point position = e.GetPosition(null);

                if (Math.Abs(position.X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||

                    Math.Abs(position.Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)

                {
                  StartDrag(e); 
                }
            }
        }

        void DragSource_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            _startPoint = e.GetPosition(null);
        }

Now you detect a drag operation, all you need to know is dropping into.

现在您检测到拖动操作,您需要知道的就是放入。

A simple scenario without any effect could be done like this.

一个没有任何影响的简单场景可以这样完成。

private void StartDrag(MouseEventArgs e)
        {
            IsDragging = true;

            DataObject data = new DataObject(System.Windows.DataFormats.Text.ToString(), "abcd");

            DragDropEffects de = DragDrop.DoDragDrop(this.DragSource, data, DragDropEffects.Move);

            IsDragging = false;
        }

I think this can get you started. I really recommend to read the complete post from the link.

我认为这可以让你开始。我真的建议您阅读链接中的完整帖子。

https://blogs.msdn.microsoft.com/jaimer/2007/07/12/drag-amp-drop-in-wpf-explained-end-to-end/

https://blogs.msdn.microsoft.com/jaimer/2007/07/12/drag-amp-drop-in-wpf-explained-end-to-end/