WPF drag and drop on a button

为君一笑 提交于 2019-12-11 11:24:03

问题


I'm writing a WPF application that has grids of buttons and I want to allow the user to drag and drop buttons between grids, possibly between different instances of the application. I've tried doing this by adding a handler to the PreviewMouseMove event on the button and then calling DoDragDrop if the left mouse button is down, but when I drag and drop the button it always ends up calling DoDragDrop twice and the drop event handler twice. Does anyone know why this happens and how to prevent it?

Here's some example XAML which demonstrates the problem:

<Window x:Class="WpfTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <DockPanel>
        <Button PreviewMouseMove="PreviewMouseMove" x:Name="m_button" Width="250">
            Hello, world!
        </Button>
        <Label Drop="Drop" AllowDrop="True">
            Drop here!
        </Label>
    </DockPanel>
</Window>

and the corresponding code:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void PreviewMouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            ++m_dragIndex;
            System.Console.WriteLine("Dragged: " + m_dragIndex.ToString());
            DragDrop.DoDragDrop(m_button, m_dragIndex, DragDropEffects.All);
            e.Handled = true;
        }
    }

    private void Drop(object sender, DragEventArgs e)
    {
        System.Console.WriteLine("Dropped: " + e.Data.GetData(typeof(Int32)).ToString());
    }

    private int m_dragIndex;
}

For a single drag, this gets written to the output:

Dragged: 1
Dragged: 2
Dropped: 2
Dropped: 1

UPDATE: I've changed the example code above to show which drop events get called when the button is dropped onto something.

UPDATE: Updated the question to include dragging between containers and application instances, since this is the motivating factor for using the DragDrop system.


回答1:


I've found a workaround for this - since the first DoDragDrop calls the second PreviewMouseMove internally, I can track whether I'm already inside a PreviewMouseMove call and ignore it if I am. This seems a bit nasty though so I'm hoping there's a better solution.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void PreviewMouseMove(object sender, MouseEventArgs e)
    {
        if(!m_inMouseMove)
        {
            m_inMouseMove = true;
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                ++m_dragIndex;
                System.Console.WriteLine("Dragged: " + m_dragIndex.ToString());
                DragDrop.DoDragDrop(m_button, m_dragIndex, DragDropEffects.All);
                e.Handled = true;
            }
            m_inMouseMove = false;
        }
    }

    private void Drop(object sender, DragEventArgs e)
    {
        System.Console.WriteLine("Dropped: " + e.Data.GetData(typeof(Int32)).ToString());
    }

    private int m_dragIndex;
    bool m_inMouseMove;
}



回答2:


I've had the same problem. I've discovered that PreviewMouseMove called twice because the first time it raised by container element (e.g. ListViewItem) and the second one - for TextBlock. So I can suggest checking the type of e.OriginalSource value as another workaround for this issue.



来源:https://stackoverflow.com/questions/15632317/wpf-drag-and-drop-on-a-button

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!