【问题标题】:How to resolve possible scheduling error with async ReactiveCommand?如何使用异步 ReactiveCommand 解决可能的调度错误?
【发布时间】:2019-05-29 15:54:06
【问题描述】:

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

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

我的视图模型:

   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,其中显示一条消息“无法获取局部变量或参数的值,因为它在此指令指针处不可用,可能是因为它已被优化掉。”

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

【问题讨论】:

  • Reactivelist 已被弃用,取而代之的是 DynamicData。没有反应列表的地方是线程安全的
  • 感谢您的提示。我在 ReactiveList 上看到过时的警告,但是有这么多新东西,只有这么多的时间来学习。很高兴尽快知道迁移到 DynamicData 的原因

标签: asynchronous command reactiveui


【解决方案1】:

。首先,如我的评论中所述,reactivelist 已被弃用。

调用 LoadUsers 命令的方式有问题。

一个是你可以在你的视图模型中做WhenActivated。您从ISupportsActivation 派生您的视图模型,当调用WhenActivated 时,您的视图将调用视图内的WhenActivated 块。有关想法,请参阅https://reactiveui.net/docs/handbook/when-activated/#viewmodels

第二种方法是使用

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

所以上面说获取LoadUsers命令,获取Execute(),它是一个observable,Switch()表示只订阅最新的,当有新的值进来时处理旧的执行,订阅我们将运行命令,并处置以可能停止。

【讨论】:

  • 不幸的是,这似乎没有帮助。我用您建议的 .Select(...).Switch() 替换了 SelectMany ,但仍然得到相同的异常。为了检查,我在模型被激活时放弃了命令的自动调用,而是将命令连接到按钮单击。还是同样的问题。
【解决方案2】:

看起来问题不在于调度,而是与异步有关。

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

【讨论】:

    猜你喜欢
    • 2018-12-06
    • 1970-01-01
    • 2021-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多