【问题标题】:Is it possible to drag and drop a UWP StorageFile to desktop, created using CreateStreamedFileFromUriAsyc是否可以将使用 CreateStreamedFileFromUriAsyc 创建的 UWP StorageFile 拖放到桌面
【发布时间】:2017-09-20 03:10:42
【问题描述】:

目标: 我想要做的是将应用程序外部的UWP应用程序中的GridView中的GridViewItem拖到桌面资源管理器中。在放置事件期间,我想从 Internet 下载一个文件并创建一个 StorageFile,用于填充 DataPackage。我希望将此StorageFile 复制到桌面。不幸的是,当延迟用于 UWP 拖放(使用 SetDataProvider)时,一旦您离开应用程序窗口,请求就会被激活,您必须使用要传输的对象填充 DataPackage。因此,在我看来,我需要使用由 CreateStreamedFileFromUriAsyc 创建的延迟类型 StorageFile

我不想每次开始进行拖放操作时都预先下载数据。我只想在实际将数据放到合法复制的地方时才下载数据。

  1. 我知道如何使用延迟请求将预先存在的StorageFile 从 UWP 拖放到资源管理器(桌面)。
  2. 我还知道如何使用CreateStreamedFileFromUriAsyc 创建一个StorageFile,它会为您提供一个StorageFile,仅在请求数据时才下载数据。

当我尝试结合这两个想法时,Windows 资源管理器给了我错误“不支持接口。”。

如果我使用完全相同的代码,但只是通过在延迟拖动处理程序期间调用 GetBasicPropertiesAsync 之类的东西来获取文件内容,则只有在我将拖动放在桌面上直到下载文件时它才有效。当拖动图标从“禁止”图标变为“复制”时,我可以看到它完成了。如果我在完成之前松开鼠标按钮,则不会发生复制,也不会引发错误。

显然,我希望拖放下载而不必在延迟处理程序上手动启动它。有任何想法吗?这可能吗?

(是的,我意识到创建正确文件扩展名的代码是错误的/不完整的,但这无关紧要......)

//DragStarted Handler in constructor
DragItemsStartedCommand = ReactiveCommand.Create<DragItemsStartingEventArgs>((e) =>
        {
            _dragItems = e.Items.Cast<ItemViewModel>();
            e.Data.Properties.Title = "Transfer file";
            e.Data.Properties.Description = "desscription of transfering a file";
            e.Data.Properties.FileTypes.Add(StandardDataFormats.StorageItems);
            e.Data.SetDataProvider(Windows.ApplicationModel.DataTransfer.StandardDataFormats.StorageItems, OnDeferredStorageFileRequestedHandler);
            e.Data.RequestedOperation = DataPackageOperation.Copy;
        });


 //Deferred request handler
    async void OnDeferredStorageFileRequestedHandler(DataProviderRequest request)
    {
        DataProviderDeferral deferral = request.GetDeferral();
        try
        {
            Task<IEnumerable<StorageFile>> task = null;
            await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
            {
                task = DownloadStorageFiles();
            });
            var result = await task;
            request.SetData(result);
        }

        catch (Exception ex)
        {
            // Handle the exception
        }

        finally
        {
            deferral.Complete();
            Debug.WriteLine("deferral complete!!!");
        }

    }

//Create StorageFile with deferred loading Task
    async Task<IEnumerable<StorageFile>> DownloadStorageFiles()
    {
        List<StorageFile> storageItems = new List<StorageFile>();
        foreach (var item in _dragItems)
        {
            var request = new RestSharp.RestRequest();
        var defaultItemType = ItemType.MSWord;
        switch (item.MimeTypeTranslated)
        {
            case ItemType.GoogleDocument:
            case ItemType.GoogleSpreadsheet:
            case ItemType.GooglePresentation:
            case ItemType.GoogleDrawing:
            case ItemType.GoogleScript:
                request.Resource = $"files/{item.File.id}/export";
                request.AddParameter("mimeType", Statics.ItemTypeDictionary.First(x => x.Value == defaultItemType).Key);
                break;
            default:
                request.Resource = $"files/{item.File.id}";
                request.AddParameter("alt", "media");
                break;
        }
        string fileName = "";
        if (item.File.name.EndsWith($".{Statics.ItemExtensionDictionary[defaultItemType]}"))
            fileName = $"{item.File.name}";
        else
            fileName = $"{item.File.name}.{Statics.ItemExtensionDictionary[defaultItemType]}";
        var uri = account.Client.GetAuthorizedUriForDownload(request);

        var thumbnail = RandomAccessStreamReference.CreateFromFile(await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///StoreLogo.png")));
        var storageFileDeferred = await StorageFile.CreateStreamedFileFromUriAsync(fileName, uri , thumbnail);
        //var props = await storageFileDeferred.GetBasicPropertiesAsync();                
         storageItems.Add(file);
        }
        return storageItems;
    }

此问题的 GitHub 重现: https://github.com/limefrogyank/DragDeferredFileToDesktop

  1. 首页是一个常规的拖到桌面的页面,因为 StorageFile(+ 基础数据)已经在 assets 文件夹中
  2. 第二页显示使用通过 CreateStreamedFileFromUriAsync 创建的 StorageFile 时生成的错误。
  3. 第三页使用相同类型的 StorageFile,但使用 hack 强制同步检索数据。桌面冻结一秒钟,直到数据准备就绪。

【问题讨论】:

  • 我对你的问题有点困惑。你能详细说明一下吗?例如,你想做什么?你如何以及为什么将两者结合起来?你用了第三方包吗?有minimal reproducible example 项目吗?
  • 我在开头添加了一段,希望能解释我想要做什么。如果有帮助,我可以尝试创建一个最小的示例项目...
  • 好的,很明显。对于“我知道如何使用延迟请求将预先存在的 StorageFile 从 UWP 拖放到资源管理器(桌面)。”我能知道你是如何实现的吗?你用ReativeUI了吗?
  • 我现在在 GitHub 上有一个复制品。链接在问题的底部。我使用我的“hack”得到了好坏参半的结果。通过示例复制,它可以工作,只是它会锁定桌面直到下载完成。仍然不是一个好结果。
  • @LeeMcPherson 您找到解决方法了吗?我还偶然发现了这张来自 Microsoft 的 Ticket,似乎他们正在处理它 => github.com/microsoft/WindowsAppSDK/issues/140

标签: winapi drag-and-drop uwp storagefile


【解决方案1】:

在最近的 Windows 更新中,UWP 应用上的存储文件拖放由系统自动处理。

example gif.

【讨论】:

  • 即使StorageFile 使用CreateStreamedFileFromUriAsyc 创建?因为如果文件是本地文件,是的,StorageFile 行为正常...但是如果StorageFile 表示远程数据流,那么当我最初发布此问题时它不起作用...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-01
  • 2012-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-08
  • 2012-02-06
相关资源
最近更新 更多