WPF拖放导致内存泄漏

4
使用Red-Gate工具,我们检测到System.Windows.DataObject正在持有对dragObject(一个框架元素)的引用,该元素已经在操作完成���长时间挂起。
如何在DragDrop.DoDragDrop后“清除”拖放对象?是否有一种方法可以传递null并使其直接穿过?
2个回答

6
我刚刚发现了这个宝石,我的解决方案是使用WeakReference来引用被拖动的数据项。
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)
{
    ....
}

哇:这是一个真正伟大的解决方案。关于它为什么有效的简短解释:DoDragDrop() 只有在拖放操作完成后才会结束执行。因此,执行 DoDragDrop() 函数的函数始终保持着对数据对象的最后强引用,并且只会在拖放操作完成后释放它。 - Dimitri C.

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仍然存在。
  • 将_dragDropData设置为成员变量非常重要。仅将其设置为局部变量是不够的:当垃圾回收器被触发时,对象可能会被处理。这会导致一个非常难以重现的错误,因为并不是因为垃圾回收器被触发了就一定会清理对象。从我看到的情况来看,只有在大量内存被分配和释放时才会清理它。

2
你不需要一个成员变量,将 SomeDragDropData 设为局部变量,然后用 GC.KeepAlive(_dragDropData) 替换 _dragDropData = null;GC.KeepAlive 方法旨在完成这个任务(保持引用一段额外的时间,以便它不会被处理但又不对数据进行任何操作)。 - Scott Chamberlain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接