如何使用异步ReactiveCommand解决可能的调度错误?

时间:2019-05-27 08:07:55

标签: asynchronous command reactiveui

我对ReactiveUI相对较新,并且正在尝试从ReactiveCommand异步执行数据库查询。据我所知,问题不在于执行异步查询,而是当我尝试将结果加载到视图模型中的ReactiveList中时。我相信这是一个调度问题,但是我对RxUI不够熟悉,无法提出正确的方法。

我尝试使用带有ObserveOn的RxApp.TaskPoolScheduler和RxApp.MainThreadScheduler订阅视图模型中的命令,但似乎都没有帮助。

我的视图模型:

   public class UsersViewModel : ReactiveObject, IRoutableViewModel
   {
      ReactiveList<LisUser> _users;
      IUserManagementService UsersService { get; }

      public IScreen HostScreen { get; }

      public ReactiveCommand<Unit, IEnumerable<LisUser>> LoadUsers { get; }

      public String UrlPathSegment => "users";

      public ReactiveList<LisUser> Users
      {
         get => _users;
         set => this.RaiseAndSetIfChanged(ref _users, value);
      } 

      public UsersSubPageViewModel(
         IScreen screen,
         IUserManagementService usersService)
      {
         HostScreen = screen ?? throw new ArgumentNullException(nameof(screen));
         UsersService = 
            usersService ?? throw new ArgumentNullException(nameof(usersService));

         Users = new ReactiveList<LisUser>();
         LoadUsers = ReactiveCommand.CreateFromTask(async () =>
         {
            return await UsersService.GetUsersAsync().ConfigureAwait(false);
         });
         LoadUsers
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(list =>
            {
               Users.Clear();
               foreach (var u in list)
               {
                  Users.Add(u);
               }
            });
      }
   }

我的观点:

   public partial class UsersView : ReactiveUserControl<UsersViewModel>
   {
      public UsersPageView()
      {
         InitializeComponent();

         this.WhenActivated(disposables =>
         {
            this.WhenAnyValue(x => x.ViewModel.LoadUsers)
               .SelectMany(x => x.Execute())
               .Subscribe()
               .DisposeWith(disposables);
         });
      }
   }

我要发生的事情是,当激活UsersView时,UsersService的GetUsers方法将异步执行并将返回的用户列表加载到Users ReactiveList中。相反,我在VS中看到一个新选项卡,标题为“找不到源”,并显示一条消息,提示“找不到RxApp.cs”。实际的异常是System.Exception,其中带有一条消息,指出“无法获取局部变量或参数的值,因为它在此指令指针处不可用,可能是因为它已被优化。”

所以,我的第一个问题是“这实际上是计划问题吗?”第二个问题是“我该如何解决?”

2 个答案:

答案 0 :(得分:0)

。首先,如我的评论所述,不推荐使用activelist。

调用LoadUsers命令的方式存在问题。

一种是您可以在视图模型中执行WhenActivated。您从ISupportsActivation派生视图模型,视图在调用WhenActivated时将在视图内部调用WhileActivated块。有关想法,请参见https://reactiveui.net/docs/handbook/when-activated/#viewmodels

第二种方法是

this.WhenAnyValue(x => x.ViewModel.LoadUsers)
               .Select(x => x.Execute())
               .Switch()
               .Subscribe()
               .DisposeWith(disposables);

因此,上面说的是获取LoadUsers命令,获取可观察到的Execute(),Switch()意味着仅先订阅最新的,并在输入新值时处置旧的execute,然后订阅运行该命令,并设置为可能停止。

答案 1 :(得分:0)

问题似乎不是在计划中,而是与异步相关。

IUserManagementService引用了一个IUserRepository,该IUserRepository本身具有一个GetUsersAsync方法来实际查询数据库。 IUserManagementService的实际实现在对IUserRepository.GetUsersAsync的调用中缺少ConfigureAwait。在单元测试中这不是问题,但是一旦涉及到UI,肯定是一个问题。