【问题标题】:ReactiveUI CancelableCommand with RestApi带有 Rest Api 的 ReactiveUI 可取消命令
【发布时间】:2017-07-03 10:55:46
【问题描述】:

我正在使用 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)))

【问题讨论】:

    标签: c# asp.net-web-api reactiveui


    【解决方案1】:

    由于我不完全知道这里的具体问题是什么,所以我只是尝试看看我能在这里做什么。

    将您的GetItemsCommand 更改为ReactiveCommand&lt;string, Unit&gt; 类型(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 的任何代码。

    作为旁注,您可以通过从命令返回您的列表并在命令的 Subscribe 块中设置 Items 属性,以稍微更清晰的关注点分离方式重写此代码:

    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(您链接的文档在订阅上调用Dispose,而不是在命令上)。传入 CancellationToken 或设置另一个 observable 以取消正在运行的命令(两者都在您的链接中)通常是实现这一目标的最干净的方法。

    例如:

    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);
    

    最后一点还没有实际测试过,但我觉得它应该可以工作:) 只是一些想法。

    【讨论】:

    • 我想我现在明白了。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-18
    • 2019-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多