ReactiveUI 6异步命令未在WPF应用程序中的后台线程上运行

视图模型

public class MyViewModel:ReactiveObject, IRoutableViewModel{ private ReactiveList _appExtensions; public MyViewModel(IScreen screen){ HostScreen = screen; AppExtensions = new ReactiveList(); GetApplicationExtensions = ReactiveCommand.CreateAsyncTask(x => _schemaService.GetApplicationExtensions()); // returns a Task<IEnumerable> GetApplicationExtensions .ObserveOn(RxApp.MainThreadScheduler) .SubscribeOn(RxApp.TaskpoolScheduler) .Subscribe(p => { using (_appExtensions.SuppressChangeNotifications()) { _appExtensions.Clear(); _appExtensions.AddRange(p); } }); GetApplicationExtensions.ThrownExceptions.Subscribe( ex => Console.WriteLine("Error during fetching of application extensions! Err: {0}", ex.Message)); } // bound to a ListBox public ReactiveList AppExtensions { get { return _appExtensions; } set { this.RaiseAndSetIfChanged(ref _appExtensions, value); } } public ReactiveCommand<IEnumerable> GetApplicationExtensions { get; protected set; } } 

并且View有一个

实现GetApplicationExtensions

  public async Task<IEnumerable> GetApplicationExtensions() { IEnumerable extensions = null; using (var client = new HttpClient()) { client.BaseAddress = BaseAddress; client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken); var response = await client.GetAsync("applications"); if (response.IsSuccessStatusCode) { var json = await response.Content.ReadAsStringAsync(); extensions = JsonConvert.DeserializeObject<IEnumerable>(json); } } return extensions; } 

从我读过的关于ReactiveUI的所有内容和我见过的所有示例(虽然新的6.0+版本中只有极少数),这应该使我的异步调用(通过HttpClient进行异步HTTP请求)在后台运行从结果返回时,在我的视图中更新并更新ListBox 。 但是,情况并非如此 – UI在异步调用期间被锁定。 我究竟做错了什么?

UPDATE

如果我将HTTP调用包装在一个Task那么一切都按预期工作 – UI根本没有挂起。 所以我的服务调用的新实现是这样的:

  public Task<IEnumerable> GetApplicationExtensions() { var extensionsTask = Task.Factory.StartNew(async () => { IEnumerable extensions = null; using (var client = new HttpClient()) { client.BaseAddress = BaseAddress; client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken); var response = await client.GetAsync("applications"); if (response.IsSuccessStatusCode) { var json = await response.Content.ReadAsStringAsync(); extensions = JsonConvert.DeserializeObject<IEnumerable>(json); } } return extensions; } return extensionsTask.Result; } 

此外,通过对我的异步服务调用的此更改,我可以从我的ReactiveCommand删除ObserveOnSubscribeOn ,如@PaulBetts suggessted。 所以我的视图模型的构造函数中的ReactiveCommand实现变为:

  GetApplicationExtensions = ReactiveCommand.CreateAsyncTask(x => _schemaService.GetApplicationExtensions()); // returns a Task<IEnumerable> GetApplicationExtensions .Subscribe(p => { using (_appExtensions.SuppressChangeNotifications()) { _appExtensions.Clear(); _appExtensions.AddRange(p); } }); 

你能展示_schemaService.GetApplicationExtensions()的实现吗?

根据它的实现方式,它可能实际上不在另一个线程上。 可以说,ReactiveCommand应该保证即使在运行异步操作之前意外烧毁CPU的异步操作也会强制进入后台线程,但在这种情况下,效率胜过防御性编程。

您不应该需要SubscribeOnObserveOn ,ReactiveCommand已经保证将在UI线程上返回值。 否则,这段代码看起来不错!

更改

  GetApplicationExtensions .ObserveOn(RxApp.MainThreadScheduler) .SubscribeOn(RxApp.TaskpoolScheduler) 

  GetApplicationExtensions .SubscribeOn(RxApp.TaskpoolScheduler) .ObserveOn(RxApp.MainThreadScheduler) 

ObserveOn应该在SubscribeOn之后

    Interesting Posts