将文件从(例如)Windows资源管理器中的文件拖放到WPF应用程序中

Dyl*_*tie 3 c# iphone wpf usb drag-and-drop

我有一个C#WPF应用程序,允许用户通过从Windows资源管理器中拖入文件并将其放在主应用程序窗口中来导入文件.

从物理磁盘拖动文件时它可以正常工作,但是当从连接的设备(如iPhone或通过USB连接的摄像头)拖动文件时,我无法识别窗口的Drop中的dragEventArgs.Data.GetFormats()返回的任何数据格式处理程序.

任何人都喜欢分享一些提示或指出一个很好的例子或演绎如何以这种方式从C#/ .NET中的"虚拟"文件系统读取/导入文件?

谢谢,

迪伦

Ray*_*rns 5

获取文件名

获取文件名很简单.只需致电:

dragEventArgs.Data.GetData("FileGroupDescriptorW")
Run Code Online (Sandbox Code Playgroud)

这将返回MemoryStream包含FILEGROUPDESCRIPTORA结构的内容.这可以解析为获取文件名. 这里这里是CodeProject项目的链接,它们向您展示了两种不同的FILEGROUPDESCRIPTORAC#解析方法,所以我不在这里详细介绍.我可能会使用第一个项目中描述的技术.

获取实际数据

要获取实际数据,请使用该FileContents格式.不幸的是,您必须使用反射来访问私有方法,或者自己编写一些COM互操作.问题是要获取数据,您必须System.Runtime.InteropServices.ComTypes.IDataObject使用设置为项索引的lindex的FORMATETC结构调用接口.不幸的是,System.Windows.DataObject的实现始终使用lindex = -1调用它.

最简单的解决方案可能是使用反射来调用WPF的私有成员DataObject.但是,请注意,在未来的.NET Framework版本中,这可能会破坏您的代码.如果这是完全不可接受的,你的另一个选择是调用RegisterDragDrop函数ole32.dll来注册一个自定义IOleDropTarget,然后直接与IDataObject传入的COM对话.这不是非常困难,但反射解决方案更容易,可能适用于许多.NET Framework的版本,这就是我将关注的内容.

以下是检索特定索引的FileContent的方法:

  1. 反映数据对象的实际类,以找到一个带有四个参数的名为"GetData"的方法
  2. 如果找不到该方法,请再次反映以查找类型的字段System.Windows.IDataObject,获取其值,然后返回步骤1(此处递归是安全的)
  3. 使用MethodInfo.Invoke"FileContents",假的,ComTypes.DVASPECT,LINDEX:调用"的GetData"你的论点找到
  4. 从返回的文件中读取文件数据 MemoryStream

以下是检索给定索引的文件内容的代码要点:

public MemoryStream GetFileContents(IDataObject dataObject, int index)
{
  MethodInfo getData = (
    from method in dataObject.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
    where method.Name=="GetData" && method.GetParameters().Length==4
    select method
  ).FirstOrDefault();

  if(getData==null)
  {
    FieldInfo innerField = (
      from field in dataObject.GetType().GetFields()
      where field.FieldType == typeof(IDataObject)
      select field
    ).FirstOrDefault();
    if(innerField==null) throw new Exception("Cannot get FileContents from DataObject of type" + dataObject.GetType());
    return GetFileContents((IDataObject)innerField.GetValue(dataObject), index);
  }

  return (MemoryStream)getData.Invoke(dataObject, new object[]
  {
    "FileContents", false,
    System.Runtime.InteropServices.ComTypes.DVASPECT.DVASPECT_CONTENT,
    index
  });
}
Run Code Online (Sandbox Code Playgroud)