如何将“IStorageItem”的实现传递给 DataPackage.SetStorageItems(items) 并且不会在 UWP 上引发 InvalidCastException?
Posted
技术标签:
【中文标题】如何将“IStorageItem”的实现传递给 DataPackage.SetStorageItems(items) 并且不会在 UWP 上引发 InvalidCastException?【英文标题】:How can I pass an implementation of "IStorageItem" to DataPackage.SetStorageItems(items) and don't get an InvalidCastException raised on UWP? 【发布时间】:2019-07-01 09:06:14 【问题描述】:我正在开发一个能够共享其文件的 UWP 应用程序。我关注了the documentation from Microsoft,解决方案效果很好。
这是我的实现:
public void ShareLocalFile(LocalFileToShare file)
DataTransferManager.GetForCurrentView().DataRequested += async (sender, args) =>
var deferral = args.Request.GetDeferral();
try
var storageFile = await StorageFile.GetFileFromPathAsync(file.FilePath).AsTask();
args.Request.Data.SetStorageItems(new[] storageFile );
finally
deferral.Complete();
;
DataTransferManager.ShowShareUI();
但是,该应用程序会存储所有名称不可读的文件,这使用户对共享感到不安。 因此,我想共享一个具有替代名称的文件,而不是在文件系统上实际重命名它,因为文件是在第三方阅读器中打开的。此外,文件很大,用新名称复制它们不是一个好的选择。
首先我认为我可以建立一个符号链接,但it's only possible with Administrator rights
然后我查看了the signature of "void DataPackage.SetStorageItems(IEnumerable value)" method 并猜测可能会传递我自己的IStorageItem 实现我做了什么:
public class StorageItemWithAlternativeName : IStorageItem
private readonly IStorageItem storageItem;
public StorageItemWithAlternativeName(IStorageItem storageItem, string alternativeItemName)
this.storageItem = storageItem;
Name = alternativeItemName;
public string Name get;
// the interface implementation omitted for briefness but it simply delegates all actions to the decorated storageItem
public static class LocalFileToShareExtensions
public static async Task<IStorageItem> GetStorageItem(this LocalFileToShare file)
var storageFile = await StorageFile.GetFileFromPathAsync(file.FilePath).AsTask();
if (!string.IsNullOrWhiteSpace(file.AlternativeFileName))
storageFile = new StorageItemWithAlternativeName(storageFile, file.AlternativeFileName);
return storageFile;
在这里我失败了。错误非常愚蠢 - SetStorageItems 方法抛出 InvalidCastException: “不支持这样的接口。 该集合包含无法转换为只读形式的项目。"
我调查了windows事件日志,发现如下条目:
Faulting application name: [MyApp].Windows.exe, version: 7.0.0.0, time stamp: 0x5bb69bfe
Faulting module name: combase.dll, version: 10.0.17763.253, time stamp: 0xa3f81b2d
Exception code: 0xc000027b
Fault offset: 0x00209931
Faulting process id: 0x4ee4
Faulting application start time: 0x01d4be3ccca1f00f
Faulting application path: [PathToMyApp].Windows.exe
Faulting module path: C:\WINDOWS\System32\combase.dll
Report Id: 35999df1-6b4f-4675-a821-a84e6ea0cfb4
Faulting package full name: [MyAppPackageName]
Faulting package-relative application ID: App
DataPackage 对象似乎与 COM 通信,所以我也在我的程序集上尝试了[assembly: [ComVisible(true)]
属性,但我没有成功。
问题是我怎样才能使系统变笨并共享一个不同名称的文件? 是否可以将我自己的实现传递给 UWP SDK 方法?因为现在它违反了the Liskov substitution principle。
我将不胜感激!
【问题讨论】:
IStorageItem 存在,因此 StorageFolder 和 StorageFile 都可以实现它。但是你不能在你的自定义类中实现它。你想要的是 StorageFile.CreateStreamedFileAsync。这使您可以创建虚拟文件。 【参考方案1】:请尝试使用带有参数readOnly:false
的重载方法SetStorageItems
,如下所示:
args.Request.Data.SetStorageItems(new[] storageFile , false);
【讨论】:
谢谢@Alexander!它使用了一个小技巧。我还必须实现来自StorageFile
的所有接口:class StorageFileWithAlternativeName : IStorageFile, IStorageItemProperties2, IStorageItem2, IStorageItemPropertiesWithProvider, IStorageFilePropertiesWithAvailability, IStorageFile2
我想其中一些是不必要的,但如果只实现IStorageItem
接口,则无法将文件附加到MailClient 中的电子邮件。 P.S. Skype 使用这种方法会崩溃,尽管我可以接受,因为我只需要 MailClient 正常工作。
酷,@GennadiySakhnyuk,!以上是关于如何将“IStorageItem”的实现传递给 DataPackage.SetStorageItems(items) 并且不会在 UWP 上引发 InvalidCastException?的主要内容,如果未能解决你的问题,请参考以下文章