【问题标题】:How to import multiple files from a smartphone in a WPF app?如何在 WPF 应用程序中从智能手机导入多个文件?
【发布时间】:2020-11-27 13:41:12
【问题描述】:

我们在 WPF 应用程序(针对 .NET Framework 4.7.2)中使用 Microsoft.Win32.OpenFileDialog 时遇到问题。

我们希望能够从通过 USB 连接到计算机的智能手机导入多个文件。但是,使用OpenFileDialog 似乎不可能这样做,因为它会触发消息框“无法从该位置打开多个项目。请尝试选择单个项目。”。您可以使用这个简单的代码复制它,并从您的智能手机中选择至少 2 张图片:

var openFileDialog = new Microsoft.Win32.OpenFileDialog();
openFileDialog.Multiselect = true;
openFileDialog.ShowDialog();

这个问题是已知的(参见herehere)并且与MTP 协议有关。使用替代“USB Mas Storage”(UMS) 连接的智能手机不会出现此问题,但现代智能手机不提供此选项。

UWP FileOpenPicker 似乎可以更好地处理多个项目的选择(请参阅 here 以了解如何在 WPF 应用程序中使用它),但我们在使用 PickMultipleFilesAsync 时会考虑 InvalidCastException。问题描述为here,答案表明FileOpenPicker 不能在 WPF .NET Framework 应用程序中使用。

正如 cmets 中所说,实现此目的的另一种方法是从 skratch 实现文件选择器,使用智能手机设备的 MTP 协议。 这种方法的缺点是 .NET 和 UWP 文件选择器提供了许多出色的功能,并且完全集成到了操作系统中。

我们已经没有办法解决这个问题了,所以我的问题是:

有没有办法在面向 .NET Framework 的 WPF 应用程序中使用 Windows 文件选择器从智能手机导入多个文件?

Microsoft Q&A 上也有人问过同样的问题。

【问题讨论】:

  • 这听起来像你被卡住了,但你总是可以实现自己的文件打开对话框并处理多个文件,即使问题比打开文件对话框更高。
  • @XAMlMAX 是的,实现一个新的文件打开对话框可能是一个解决方案,但这意味着有一个专用的智能手机导入窗口,这对我们来说不是最好的。我希望找到一个“官方”的解决方案。作为记录,Microsft Edge 具有相同的限制(当以 Web 表单导入文件时),而 Microsoft Word 处理它(我猜它使用 UWP pciker)。
  • 实际上,一旦你自己实现了文件选择器,你就可以在你的应用程序中使用它。除了添加处理这些边缘情况的功能之外,它不会影响任何事情。我知道您所说的“官方”是什么意思,但我认为这更多地与 og 的实施方式有关,并且要完成这项工作,您可能需要做一些 PInvoke 魔术。我假设你有服务背后的文件选择器。
  • 是的,我将为所有应用程序提供一个自定义文件选择器。我看到这个方法的主要缺点是 Windows 默认文件选择器有很多很棒的功能(访问快速访问文件夹、地址栏、功能区、搜索栏等),效果很好并且随着视窗。实现所有这些并不是一项简单的任务。
  • @XAMlMAX 我使用 IFileOpenDialog 接口找到了我的问题的答案。我正在读回你的 cmets,也许这就是你的想法?我不知道您可以通过这种方式自定义 Windows 文件选择器。

标签: .net wpf openfiledialog mtp fileopenpicker


【解决方案1】:

我回复有点晚了,但是感谢Microsoft Q&A thread,我找到了解决方案。

据我所知,无法使用Microsoft.Win32.OpenFileDialog 从 MTP 设备中选择多个文件,因为您无法设置所有 IFileOpenDialog 选项。

因此,您需要使用自己的IFileOpenDialog 来设置选项:一定要添加FOS_ALLOWMULTISELECT 选项并删除FOS_FORCEFILESYSTEM

ComFileDialog.IFileOpenDialog fileOpenDialog = null;
ComFileDialog.IShellItemArray shellItemArray = null;
ComFileDialog.IShellItem shellItem = null;
try
{
    // Set options
    fileOpenDialog = (ComFileDialog.IFileOpenDialog)new ComFileDialog.FileOpenDialogRCW();
    fileOpenDialog.GetOptions(out var options);
    options |= ComFileDialog.FOS_ALLOWMULTISELECT | ComFileDialog.FOS_FILEMUSTEXIST | ComFileDialog.FOS_PATHMUSTEXIST;
    fileOpenDialog.SetOptions(options);

    // Show window
    if (fileOpenDialog.Show() != ComFileDialog.S_OK)
    {
        return;
    }

    // Get results
    if (fileOpenDialog.GetResults(out shellItemArray) != ComFileDialog.S_OK)
    {
        return;
    }

    uint items = 0;
    if (shellItemArray.GetCount(out items) != ComFileDialog.S_OK)
    {
        return;
    }

    // Result loop
    for (uint item = 0; item < items; item++)
    {
        try
        {
            if (shellItemArray.GetItemAt(item, out shellItem) != ComFileDialog.S_OK)
            {
                continue;
            }

            // Use the IShellItem
        }
        finally
        {
            if (shellItem != null)
            {
                Marshal.ReleaseComObject(shellItem);
                shellItem = null;
            }
        }
    }
}
finally
{
    if (fileOpenDialog != null)
    {
        Marshal.ReleaseComObject(fileOpenDialog);
    }
    if (shellItemArray != null)
    {
        Marshal.ReleaseComObject(shellItemArray);
    }
    if (shellItem != null)
    {
        Marshal.ReleaseComObject(shellItem);
    }
}

您可以在 pinvoke.net 上找到 Window Shell API 接口:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-09
    • 1970-01-01
    相关资源
    最近更新 更多