我正在尝试通过拖放操作从数据库传递文件,并采用多种格式:
前者对于DataObject
很简单,而后者可以使用VirtualFileDataObject
完成。但是,VirtualFileDataObject
所提供的API不如DataObject
那样方便,而且我不确定如何将相同的信息传递给它(或者是否完全有可能)。
具体来说,我的做法如下:
[Serializable]
private class FileDragDropInfo
{
public int FileID { get; set; }
public string FileName { get; set; }
}
[Serializable]
private class FileDragDropInfoArray
{
public FileDragDropInfo[] Files { get; set; }
}
[..]
var data = new DataObject();
data.SetData(new FileDragDropInfoArray { .Files = items.ToArray() });
而后者如下:
var vData = new VirtualFileDataObject.VirtualFileDataObject();
vData.SetData(items.Select(i => new VirtualFileDataObject.VirtualFileDataObject.FileDescriptor
{
Name = i.FileName,
StreamContents = (s) => { /* download the stream here */ }
}));
这两个都是单独工作的。
但是,不幸的是,VirtualFileDataObject
缺少像GetData()
这样的方法来将格式重新添加到原始DataObject
中。相反,VirtualFileDataObject
(不同于DataObject
)也没有执行转换的重载。
但是,确实有此重载:
public void SetData(short dataFormat, IEnumerable<byte> data);
我猜第一个参数与System.Windows.Forms.DataFormats.Format中的Id
属性相同,因此它的第一部分可能起作用:
foreach (var format in data.GetFormats().Select(f => System.Windows.Forms.DataFormats.GetFormat(f))
{
vData.SetData(format.Id, /* how do I pass the data? */);
}
但是,在浏览了System.Windows.Forms.DataObject的源代码之后,我不知所措,它在哪里以及如何对传递的数据进行转换/序列化,以便我可以将其作为第二个参数作为{ {1}}。相关代码(例如byte[]
和整个SaveDataToHandle()
类也是私有的,因此我将无法直接调用它们(除非反射)。
如果我需要做的只是传递这样的句柄,我实际上并没有尝试过。我在正确的轨道上吗?
将其他格式传递给DataStore
会完全有效吗?还是两者根本不兼容? (或者我必须扩展VirtualFileDataObject
来支持这一点吗?)
答案 0 :(得分:1)
我至少在DataFormats.Serializable
上已经弄清楚了,暂时将它实现为扩展方法ImportDataObject
:
public static class VirtualFileDataObjectExtensions
{
public static void ImportDataObject(this ref VirtualFileDataObject.VirtualFileDataObject virtualFileDataObject, DataObject dataObject)
{
if (virtualFileDataObject == null)
throw new ArgumentNullException(nameof(virtualFileDataObject));
if (dataObject == null)
throw new ArgumentNullException(nameof(dataObject));
foreach (var format in dataObject.GetFormats())
{
short formatIDShort = _GetShortFormatID(format);
var data = dataObject.GetData(format);
// we only support Serializable for now
if (format.Equals(DataFormats.Serializable) || data is ISerializable || data?.GetType().IsSerializable)
virtualFileDataObject.SetData(formatIDShort, _SerializeDataObject(data));
}
}
private static short _GetShortFormatID(string format)
{
// unfortunately, .NET uses an int, but ushort would be correct
ushort formatID = System.Convert.ToUInt16(DataFormats.GetFormat(format).Id & 0xFFFF);
short formatIDShort;
// and VirtualFileDataProvider takes a short instead of a ushort
unchecked { formatIDShort = (short)formatID; }
return formatIDShort;
}
private readonly static byte[] _serializedObjectID = new Guid(0xFD9EA796, 0x3B13, 0x4370, 0xA6, 0x79, 0x56, 0x10, 0x6B, 0xB2, 0x88, 0xFB).ToByteArray();
private static byte[] _SerializeDataObject(object data)
{
using (MemoryStream ms = new MemoryStream())
{
using (BinaryWriter binaryWriter = new BinaryWriter(ms))
{
binaryWriter.Write(_serializedObjectID);
var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
formatter.Serialize(ms, data);
}
ms.FlushAsync();
return ms.ToArray();
}
}
}
此代码可能需要进行一些清理,但对我而言非常有用。