代码之家  ›  专栏  ›  技术社区  ›  Sören Kuklau Keith Boynton

合并/转换virtualfiledataobject和system.windows.forms.dataobject

  •  0
  • Sören Kuklau Keith Boynton  · 技术社区  · 6 年前

    我正在尝试在拖放操作期间从数据库传递文件,其格式多种多样:

    • 如果拖动发生在同一进程中,只需传递文件ID;目标控件将知道如何处理它。
    • 如果拖动到其他应用程序,则在拖放时传递流以下载文件。

    前者很简单 DataObject ,后者可以使用 VirtualFileDataObject . 然而, 虚拟文件数据对象 没有比 数据对象 我不确定如何将同样的信息传递给它(或者是否有可能)。

    具体来说,我是这样做的:

    [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 */ }
    }));
    

    它们都是单独工作的。

    然而, 虚拟文件数据对象 不幸的是,缺乏这样的方法 GetData() 将该格式添加回原始格式 数据对象 . 相反, 虚拟文件数据对象 也(不像) 数据对象 )没有执行转换的重载。

    但是,它确实有这样的过载:

    public void SetData(short dataFormat, IEnumerable<byte> data);
    

    我猜第一个参数和 Id System.Windows.Forms.DataFormats.Format中的属性,因此第一部分可能有效:

    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的源代码之后,我不知道它在哪里以及如何转换/序列化传递的数据,这样我就可以将它作为第二个参数作为 byte[] . 相关代码 SaveDataToHandle() 以及整个 DataStore 类也是私有的,所以我不能直接调用它们(除非反射)。

    实际上我没有 尝试 如果我要做的就是通过这样一个把手。我走对了吗?

    将传递其他格式到 虚拟文件数据对象 工作 完全 或者两者根本不相容?(或者我要延期吗) 虚拟文件数据对象 为了支持这一点?)

    1 回复  |  直到 6 年前
        1
  •  1
  •   Sören Kuklau Keith Boynton    6 年前

    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();
            }
        }
    }