WinJS - WinRT组件 - 该应用程序称为为不同线程编组的接口

时间:2014-04-25 09:28:38

标签: c# windows-8 windows-runtime winjs

我正在使用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。

所以,我希望回答两个问题:

  1. 在高层次上,我是否应该尝试在UI线程上运行WinRT库代码?从而使它同步?如果这是正确的,那么使我的WinRT代码处理写入文件系统的最有效方法是什么,以这种方式行事(下面的代码)
  2. 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;
        });
    };
    
    1. 如果1错了,我应该尝试让RT代码保持异步,但是在与我的JS UI代码相同的线程上运行,我怎样才能获得对该线程的引用,然后启动RT代码中的方法?我已经尝试了一些运行RT代码的Dispatcher.RunAsync()方法,但是当我需要通过WinRT框架方法获取对IStorageFile的引用时,我才会失败。
    2. 任何想法都非常感激。

1 个答案:

答案 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()进行调用。然后(...)。这可能会简化您的代码。