C# WPF拖放到按钮上

C# WPF拖放到按钮上,c#,wpf,button,drag-and-drop,C#,Wpf,Button,Drag And Drop,我正在编写一个具有按钮网格的WPF应用程序,我希望允许用户在网格之间,可能在应用程序的不同实例之间拖放按钮。我尝试通过在按钮上的PreviewMouseMove事件中添加一个处理程序,然后在鼠标左键按下时调用DoDragDrop,但当我拖放按钮时,它总是会调用DoDragDrop两次,并调用drop事件处理程序两次。有人知道为什么会发生这种情况以及如何预防吗 下面是一些演示问题的XAML示例: <Window x:Class="WpfTest.MainWindow" xml

我正在编写一个具有按钮网格的WPF应用程序,我希望允许用户在网格之间,可能在应用程序的不同实例之间拖放按钮。我尝试通过在按钮上的PreviewMouseMove事件中添加一个处理程序,然后在鼠标左键按下时调用DoDragDrop,但当我拖放按钮时,它总是会调用DoDragDrop两次,并调用drop事件处理程序两次。有人知道为什么会发生这种情况以及如何预防吗

下面是一些演示问题的XAML示例:

<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>
对于单次拖动,将写入输出:

Dragged: 1
Dragged: 2
Dropped: 2
Dropped: 1
更新:我更改了上面的示例代码,以显示当按钮被放置到某个对象上时调用了哪些放置事件


更新:更新了问题,将容器和应用程序实例之间的拖动包括在内,因为这是使用DragDrop系统的动力因素。

我找到了解决方法-因为第一个DoDragDrop在内部调用第二个PreviewMouseMove,我可以跟踪我是否已经在PreviewMouseMove调用中,如果已经在,则忽略它。这似乎有点令人讨厌,所以我希望有更好的解决办法

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;
}

我也有同样的问题。我发现PreviewMouseMove调用了两次,因为第一次是由容器元素(例如ListViewItem)引发的,第二次是由TextBlock引发的。因此,我建议检查e.OriginalSource值的类型,作为此问题的另一个解决方法。

使用PreviewMouseDown事件开始拖动,而不是PreviewMouseMove事件!但我不认为这是正确的方法,看看这个答案,我不担心,第二个DoDragDrop电话会阻止第一个。当您实现Drop方法时,它只会触发一次。你不会注意到UI上的第二个DoDragDrop调用。SvenG:我希望如此,但当按钮被放到某个东西上时,它似乎会生成两个丢弃的事件。我已经更新了示例代码以显示这一点。@sine:将其更改为PreviewMouseDown确实会停止双重调用,但这意味着当用户单击按钮时,会启动拖动。理想情况下,我只希望在用户按住按钮并稍微移动鼠标时启动它。谢谢你的链接,我会查出来的。
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;
}