WPF - insufficient memory when doing copy/paste vs drag/drop with view model data
I have a TreeView
that provides drag and drop as well as copy/paste functionality. 开发者_开发百科 I extended TreeViewItem
to provide that functionality.
The drag and drop works fine. The tree is bound to a view model, and the drag is initiated in the TreeViewItem
custom class such as:
protected override void OnMouseMove(MouseEventArgs e)
{
// ...
if (canDrag)
{
DragDrop.DoDragDrop(this, DataContext, DragDropEffects.Copy);
e.Handled = true;
}
}
The drop is initiated such as:
protected override void OnDrop(DragEventArgs e)
{
// ...
Paste(e.Data);
e.Handled = true;
}
which calls a paste method that takes in an IDataObject
such as:
protected void Paste(IDataObject data)
{
// ...
if (data.GetDataPresent(typeof(FooViewModel)) == true)
{
// process Foo drop
copiedFoo = data.GetData(typeof(FooViewModel)) as FooViewModel;
// ...
}
}
The copy/paste operation is set up as follows. The copy is initiated in the TreeViewItem
custom class such as:
void CopyExecuted(object sender, ExecutedRoutedEventArgs e)
{
Clipboard.Clear();
Clipboard.SetData(DataContext.GetType().ToString(), DataContext);
}
The paste is initiated such as:
void PasteExecuted(object sender, ExecutedRoutedEventArgs e)
{
Paste(Clipboard.GetDataObject());
}
calling the same paste method with IDataObject
above.
Issue: The same paste method fails at the GetData()
call with an Insufficient memory to continue the execution of the program message when called from a copy/paste operation. I've even passed in an empty view model instance to the clipboard, with the same insufficient memory result.
There has been a known VS2010 issue similar to this, explained here. I installed that hotfix, but the memory issue still persists.
Any ideas? Should I be interacting with the Clipboard
differently? Thanks!
I had this issue in the past, and it has to do with storing an object in the ClipBoard. I can't remember exactly why, but I needed to serialize my object and store the byte[]
in the clipboard instead of the object itself.
The code I used looked something like this:
Writing:
byte[] data = SerializationHelpers.SerializeToBinary<TreeNodeBase>(
selectedTreeNode,
new Type[] { typeof(TreeNodeA), typeof(TreeNodeB),typeof(TreeNodeC)}
);
Clipboard.SetDataObject(data, true);
Reading:
IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(typeof(byte[])))
{
MyClass obj = SerializationHelpers.DeserializeFromBinary<TreeNodeBase>(
(byte[])data.GetData(typeof(byte[])),
new Type[] {typeof(TreeNodeA), typeof(TreeNodeB),typeof(TreeNodeC)}
);
}
Serialization Classes
public static byte[] SerializeToBinary<T>(T obj, Type[] extraTypes)
{
if (obj == null)
return null;
using (MemoryStream ms = new MemoryStream())
{
DataContractSerializer dcs = new DataContractSerializer(typeof(T), extraTypes);
dcs.WriteObject(ms, obj);
return ms.ToArray();
}
}
public static T DeserializeFromBinary<T>(byte[] data, Type[] extraTypes)
{
if (data.Length == 0)
return default(T);
using (MemoryStream ms = new MemoryStream())
{
ms.Write(data, 0, data.Length);
ms.Seek(0, 0);
DataContractSerializer dcs = new DataContractSerializer(typeof(T), extraTypes);
return (T)dcs.ReadObject(ms);
}
}
精彩评论