使用 Rest Api 的 ReactiveUI 可取消命令

ReactiveUI CancelableCommand with RestApi

我正在研究 MVVM 应用程序并尝试将文本框文本更改注册到 运行 每次在此文本框上发生新更改时都可以取消的命令。 在 Reactive Extension 中,它是通过类似这样的 Switch 方法完成的:

Observable.FromEventPattern<PropertyChangedEventArgs>(this, nameof(PropertyChanged))
            .Where(a => a.EventArgs.PropertyName == nameof(Item))
            .Select(a => Item)
            .DistinctUntilChanged()
            .Throttle(TimeSpan.FromSeconds(0.5))
            .ObserveOn(SynchronizationContext.Current)
            .Do(x => { Items= null; })
            .ObserveOn(Scheduler.Default)
            .Select(item => { return Observable.FromAsync(cancellationToken => _itemService.GetItemsAsyncWithCancelation(item, cancellationToken)); })
            .Switch()
            .ObserveOn(SynchronizationContext.Current)
            .Subscribe(items => Items = items);

当我尝试用 ReactiveUi 做同样的事情时,这就是我到目前为止的想法:

public ReactiveCommand GetItemsCommand { get; set; }
GetTowaryCommand = ReactiveCommand
       .CreateFromTask<string>(async (x,cancelationToken) => Items = await _itemService.GetItemsAsyncWithCancelation(x.ToString(),cancelationToken));

this.WhenAnyValue(vm => vm.Item)
       .Throttle(TimeSpan.FromSeconds(0.5))
       .Do(_=> GetTowaryCommand.Dispose())
       .ObserveOn(SynchronizationContext.Current)
       .InvokeCommand(GetItemsCommand);

它正在运行,但我不确定是否正确取消了 RestApi 调用。 我试图遵循 ReactiveUI 文档中的示例: https://docs.reactiveui.net/en/user-guide/commands/canceling.html 但不知道如何将字符串参数 (x) 传递给 restApi 方法:

GetItemsCommand
   .CreateFromObservable<string>(() => Observable.StartAsync(async (token) => Items = await _itemService.GetItemsAsyncWithCancelation(x.ToString(), token)))

因为我不太清楚这里的具体问题是什么,我就试试看看我能在这里做什么。

将您的 GetItemsCommand 更改为 ReactiveCommand<string, Unit> 类型(string 进入,Unit 退出)。然后你可以说:

GetItemsCommand.CreateFromObservable<string,Unit>(x =>
    Observable.StartAsync(async (token) => 
        Items = await _itemService.GetItemsAsyncWithCancelation(x.ToString(), token)))

InvokeCommand 会自动将参数传递给命令(如果有的话)(即 Observable.Return("hello").InvokeCommand(GetItemsCommand) 会将 "hello" 传递给命令),因此您可能需要修改任何内容代码调用 GetItemsCommand.

作为旁注,您可以通过从命令返回列表并在命令的 Items 属性 中设置 Items 属性 =21=]块:

public ReactiveCommand<string, IEnumerable<T>> GetItemsCommand { get; set; }

GetItemsCommand.CreateFromObservable<string, IEnumerable<T>>(x =>
    Observable.FromAsync(token =>
        _itemService.GetItemsAsyncWithCancelation(x.ToString(), token)));

// always runs on UI thread
GetItemsCommand.Subscribe(x => Items = x);

此外,您通常不应手动调用 ReactiveCommand.Dispose(您 link 编辑的文档在 订阅 上调用 Dispose,而不是在 命令 上)。传入 CancellationToken 或设置另一个可观察对象以取消 运行 命令(两者都在您的 link 中)通常是实现该目的的最简洁方法。

例如:

var stream = this.WhenAnyValue(vm => vm.Item)
    .Throttle(TimeSpan.FromSeconds(0.5))
    .DistinctUntilChanged();

stream
    .InvokeCommand(GetItemsCommand);

GetItemsCommand.CreateFromObservable<string, IEnumerable<T>>(x =>
    Observable
        .FromAsync(token => _itemService.GetItemsAsyncWithCancelation(x.ToString(), token))
        .TakeUntil(stream));

GetItemsCommand.Subscribe(x => Items = x);

最后一点还没有真正测试过,但我觉得它应该有用 :) 只是一些想法。