我正在使用C#中的WinRT组件进行工作,我不是异步地从WinJS调用。
我正在调用一个库,当调用它时会抛出The application called an interface that was marshalled for a different thread
异常。我理解这是运行库代码的线程的一个问题,通过运行JS代码的UI线程。
我在这里发现了一些线程,其中提到了这可能起作用的方式(Run code on UI thread in WinRT等),但这些线程都没有涉及从WinJS调用代码,它们都倾向于XAML。
所以,我希望回答两个问题:
RT代码
public IAsyncOperation<string> ButtonPress()
{
return SaveSpreadsheet().AsAsyncOperation();
}
private async Task<string> SaveSpreadsheet()
{
var res = false;
try
{
CreateSpreadsheet();
AddSomeContentToASheet();
var folder = KnownFolders.DocumentsLibrary;
var outFile = await folder.CreateFileAsync("New.xls", CreationCollisionOption.ReplaceExisting);
res = await book.SaveAsAsync(outFile, ExcelSaveType.SaveAsXLS);
book.Close();
engine.Dispose();
}
catch (Exception e)
{
return e.Message;
}
return "Success! " + res;
}
JS代码
button.onclick = function () {
var rtComponent = new WindowsRuntimeComponent1.Class1();
rtComponent.buttonPress().then(function (res) {
document.getElementById('res').innerText = "Export should have: " + res;
});
};
Dispatcher.RunAsync()
方法,但是当我需要通过WinRT框架方法获取对IStorageFile
的引用时,我才会失败。任何想法都非常感激。
答案 0 :(得分:1)
我相信你所缺少的是对Task.Run的调用,这实际上是创建了一个Task,它将在一个单独的线程上运行操作并进行编组。
也就是说,你的SaveSpreadsheet函数说它正在返回Task但实际上并没有在任何地方创建Task,因此只返回一个字符串。以下是组件中异步函数的一般结构:
public IAsyncOperation<string> SomeMethodAsync(int id)
{
var task = Task.Run<string>(async () =>
{
var idString = await GetMyStringAsync(id);
return idString;
});
return task.AsAsyncOperation();
}
所以我认为你只需要改变SaveSpreadsheet来返回一个String(你的代码已经在做了,所以只需将Task更改为String),并使ButtonPress看起来像这样:
public IAsyncOperation<string> ButtonPress()
{
var task = Task.Run<string>(async () =>
{
return await SaveSpreadsheet();
});
return task.AsAsyncOperation();
}
顺便提一下,我在MSPress的免费电子书的第18章中介绍了这个主题,使用HTML,CSS和JavaScript编写Windows应用程序,第2版,http://aka.ms/BrockschmidtBook2。
P.S。如果您的组件没有理由使用new进行实例化,那么您可以将静态键盘添加到ButtonPress(即公共静态IAsyncOperation ButtonPress()),然后使用完全限定名称WindowsRuntimeComponent1.Class1.buttonPress()进行调用。然后(...)。这可能会简化您的代码。