拖放中的WPF内存泄漏

时间:2012-05-18 02:21:13

标签: wpf

使用Red-Gate工具,我们检测到System.Windows.DataObject持有对一个dragObject(一个框架元素)的引用,该对象从完成后的操作中徘徊不前。

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

2 个答案:

答案 0 :(得分:5)

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

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

然后在drop

var draggedItem = e.Data.GetData(this.format.Name) as WeakReference;
if (draggedItem != null && draggedItem.IsAlive)
{
    ....
}

答案 1 :(得分:1)

首先a big thanks to Ian Oakes for his solution。我需要一个轻微的变体:我必须确保丢弃始终有效,即使垃圾收集器同时运行。这是解决方案:

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成为成员变量非常重要。仅仅使它成为局部变量是不够的:当触发垃圾收集器时,对象可能被处置掉。这导致很难重现错误,因为它不是因为垃圾收集器被触发,对象必然被清除。从我看到的情况来看,只有在分配和释放大量内存时才会清理它