中从后台线程访问

中从后台线程访问

本文介绍了在 UWP 中从后台线程访问 UI 的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当尝试将数据添加到 ObservableCollection(x:Binded in XAML 到 UI 上的 ListView)时,我收到此错误:应用程序调用了为不同线程编组的接口(来自 HRESULT 的异常: 0x8001010E (RPC_E_WRONG_THREAD))

When trying to add data to an ObservableCollection, which is x:Binded in XAML to a ListView on the UI, I get this error:The application called an interface that was marshalled for a different thread (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

我的应用实现了 MVVM.VieModel 使用事件处理程序提取数据.我尝试了各种 SO 和其他解决方案,例如:

My app implements MVVM. VieModel pulls data with an eventhandler. I have tried various SO and other solutions, such as:

var ignored = Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,() =>ViewList.Add(msg));

这给出了错误:Current.Get == null

无法直接访问 Dispatcher,因为它在 ViewModel 中被调用.也没有 .Invoke 或 .BeginInvoke 访问权限,我可以找到建议的几种解决方案.

Can't access Dispatcher directly, as it is being called in the ViewModel. Also no .Invoke or .BeginInvoke access that I could find which several solutions suggested.

我尝试使用 DispatcherTimer,根据:从非 UI 线程更新 ObservableCollection.尝试在 ViewModel 中实例化 DispatcherTimer 以访问 UI 线程时,我收到 "WRONG_THREAD" 错误消息:

I tried using DispatcherTimer, as accoring to: Updating ObservableCollection from non UI thread. I get the "WRONG_THREAD" error message when trying to instantiate DispatcherTimer in the ViewModel, to access the UI thread:

disPatchTimer = new DispatcherTimer();

有一个建议行得通,很多人都赞成:该应用程序调用了一个为不同线程编组的接口 - Windows 应用商店应用程序

There is one suggestion that works, which many have upvoted here: The application called an interface that was marshalled for a different thread - Windows Store App

Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
    {
        // Your UI update code goes here!
    }
);

哪个至少看起来不像创造者"为了正确使用代码而想到的优雅解决方案?

Which does not, at least, look like an elegant solution the "creators" had in mind to properly use code?

推荐答案

您同时提到了拉动"和事件".事件本质上是推送"系统 - 事件被推送到您的代码.但是,有些系统会通过事件产生异步结果,因此我假设这就是您在此处处理的内容,因为您指定了拉取"数据.

You mention both "pull" and "event". Events are by nature "push" systems - the event is pushed to your code. However, there are some systems that produce asynchronous results via an event, so I assume that is what you're dealing with here since you specify the data is "pulled".

如果这是正确的,那么最好的解决方案是首先为基于事件的异步编写一个包装器,使其成为基于任务的异步.如果您的数据服务如下所示:

If this is correct, then the best solution is to first write a wrapper for the event-based asynchrony so it becomes task-based asynchrony. If you have a data service that looks like this:

class MyDataService
{
  public void DownloadData();
  public event MyDataArrivedEventHandler MyDataArrived;
}

然后包装器看起来像这样:

then the wrapper would look something like this:

public static Task<MyData> GetMyDataAsync(this MyDataService service)
{
  var tcs = new TaskCompletionSource<MyData>();
  MyDataArrivedEventHandler handler = null;
  handler = (s,e) =>
  {
    service.MyDataArrived -= handler;
    if (e.Error != null)
      tcs.TrySetException(e.Error);
    else
      tcs.TrySetResult(e.Data);
  };
  service.MyDataArrived += handler;
  service.DownloadData();
  return tcs.Task;
}

一旦你有了一个基于任务的异步模式方法,那么使用它并更新你的视图模型就很简单了:

Once you have a Task-based asynchronous pattern method, then consuming it and updating your viewmodel is straightforward:

// From UI thread.
var data = await service.GetMyDataAsync();
viewModel.AddRange(data); // or whatever

这种方法允许您使用 await 的上下文捕获特性,这样您就不必自己进行任何线程转换.

This approach allows you to use the context-capturing nature of await so that you don't have to do any thread transitions yourself.

这篇关于在 UWP 中从后台线程访问 UI 的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 05:48