使用 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);
最后一点还没有真正测试过,但我觉得它应该有用 :) 只是一些想法。
我正在研究 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);
最后一点还没有真正测试过,但我觉得它应该有用 :) 只是一些想法。