4

使用 Red-Gate 工具,我们检测到 System.Windows.DataObject 持有对拖拽对象(一个框架元素)的引用,该引用在操作完成后就一直挂着。

一旦 DragDrop.DoDragDrop,如何“清除”拖动对象?有没有办法通过这个传递一个空值并让它直接通过?

4

2 回答 2

6

我自己刚刚发现了这个 gem,我的解决方案是对被拖动的数据项使用 Wea​​kReference。

DataObject data = new DataObject(new WeakReference(this.draggedData));
DragDrop.DoDragDrop((DependencyObject)sender, data, DragDropEffects.Move);

然后在下降

var draggedItem = e.Data.GetData(this.format.Name) as WeakReference;
if (draggedItem != null && draggedItem.IsAlive)
{
    ....
}
于 2012-12-20T06:39:53.787 回答
1

首先非常感谢 Ian Oakes 的解决方案。然而,我需要一个轻微的变体:我必须确保丢弃始终有效,即使垃圾收集器同时运行。这是解决方案:

public partial class DragDropDemo : Window
{
    private SomeDragDropData _dragDropData;

    private void OnMouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            _dragDropData = new SomeDragDropData { Text = "Some drag data" };
            var dataObject = new DataObject("SomeObjectTypeId", new WeakReference<SomeDragDropData>(_dragDropData));
            DragDrop.DoDragDrop((DependencyObject)sender, dataObject, DragDropEffects.Move);
            _dragDropData = null;
        }
    }

    private void OnDrop(object sender, DragEventArgs e)
    {
        var weakReferenceData = e.Data.GetData("SomeObjectTypeId") as WeakReference<SomeDragDropData>;
        if (weakReferenceData != null && weakReferenceData.IsAlive)
            MessageBox.Show(weakReferenceData.Target.Text);
    }
}

public class SomeDragDropData
{
    public string Text;
}

一些备注:

  • 之所以可行,是因为 DoDragDrop 会一直阻塞,直到用户触发拖放操作。因此,只有在拖放操作完全完成后,_dragDropData 才会变为 null。
  • 使 _dragDropData 成为成员变量非常重要。仅仅将其设为局部变量是不够的:当触发垃圾收集器时,对象可能会被释放。这导致了一个非常难以重现的错误,因为并不是因为垃圾收集器被触发,对象就必须被清理。据我所见,只有在分配和释放大量内存时才会清理它
于 2013-04-29T07:56:30.707 回答