2012-05-18 4 views
4

Используя инструменты Red-Gate, мы обнаружили, что файл System.Windows.DataObject содержит ссылку на объект dragObject (элемент структуры), который висит вокруг от операции с тех пор, как она завершена.Утечка памяти WPF от перетаскивания

Как один «очистить» объект перетаскивания после DragDrop.DoDragDrop? Есть ли способ пропустить нуль через это и пропустить это?

ответ

5

Я только что открыл этот камень, мое решение состояло в том, чтобы использовать 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) 
{ 
    .... 
} 
+0

Wow: это действительно прекрасное решение. Краткое объяснение того, почему это работает: DoDragDrop() завершит выполнение только после завершения операции перетаскивания. Поэтому функция, которая выполняет DoDragDrop(), всегда содержит последнюю сильную ссылку на объект данных и будет освобождать ее только после завершения операции перетаскивания. –

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 членом переменной. Просто сделать его локальной переменной недостаточно: при запуске сборщика мусора объект может получить. Это приводит к очень трудно воспроизвести ошибку, потому что это происходит не потому, что сборщик мусора запускается, что объект обязательно очищается. Из того, что я видел, он только очищается, когда большая память распределяется и освобождается
+2

Вам не нужна переменная-член, создайте локаль 'SomeDragDropData', затем замените' _dragDropData = null; 'на' GC.KeepAlive (_dragDropData) '. Метод ['GC.KeepAlive'] (http://msdn.microsoft.com/en-us/library/system.gc.keepalive.aspx) предназначен для выполнения этой точной работы (сохраняя ссылку на дополнительную длину так что он не становится утилизированным, но ничего не делает с данными) –

Смежные вопросы