取消ReactiveUI ViewModel中的异步任务(ReactiveObject)

时间:2014-06-08 14:38:53

标签: c# mvvm reactiveui cancellation

我目前正在尝试使用 ReactiveUI (5.5.1),并且我创建了一个ViewModel(ReactiveObject的子类),它可用作自动完成功能用于位置搜索(改编自mikebluestein/ReactiveUIDemo on github)。每次查询文本更改时,都会调用REST服务,该服务返回已提交查询的匹配位置。

问题:正如您在下面的代码中所看到的,DoSearchAsync(string query, CancellationToken cancellationToken)是可取消的,但是,我不确定如何(以及代码中的位置)实际取消任何搜索 - 因此使用CancellationToken.None atm。在这个特定的用例中取消请求似乎有点过分,但我想知道如何在这个reactiveUI / async-Task场景中启用取消。

代码:

public class ReactiveLocationSearchViewModel : ReactiveObject {

readonly ReactiveCommand searchCommand = new ReactiveCommand();

public ReactiveCommand SearchCommand { get { return searchCommand; } }

string query;

public string Query
{
    get { return query; }
    set { this.RaiseAndSetIfChanged(ref query, value); }
}

public ReactiveList<Location> ReactiveData { get; protected set; }

public ReactiveLocationSearchViewModel()
{
    ReactiveData = new ReactiveList<Location>();
    var results = searchCommand.RegisterAsyncTask<List<Location>>(async _ => await DoSearchAsync(query, CancellationToken.None));

    this.ObservableForProperty<ReactiveLocationSearchViewModel, string>("Query")
        .Throttle(new TimeSpan(700))
        .Select(x => x.Value).DistinctUntilChanged()
        .Where(x => !String.IsNullOrWhiteSpace(x))
        .Subscribe(searchCommand.Execute);

    results.Subscribe(list =>
    {
        ReactiveData.Clear();
        ReactiveData.AddRange(list);
    });
}

private async Task<List<Location>> DoSearchAsync(string query, CancellationToken cancellationToken)
{
    // create default empty list
    var locations = new List<Location>();

    // only search if query is not empty
    if (!string.IsNullOrEmpty(query))
    {
        ILocationService service = ServiceContainer.Resolve<ILocationService>();
        locations = await service.GetLocationsAsync(query, cancellationToken);
    }

    return locations;
}

}

2 个答案:

答案 0 :(得分:3)

RxUI 5.x没有内置功能,但很容易伪造:

var results = searchCommand.RegisterAsync<List<Location>>(
    _ => Observable.StartAsync(ct => DoSearchAsync(query, ct)));

在RxUI v6中,它内置于:

searchCommand = ReactiveCommand.CreateAsyncTask(
    (_, ct) => DoSearchAsync(query, ct));

答案 1 :(得分:0)

ReactiveUI 9.x的更新:

定义属性

// using ReactiveUI.Fody
[Reactive]
public ReactiveCommand<TQuery, IEnumerable<TResult> SearchCommand { get; set; }

private CompositeDisposable Disposables { get; } = new CompositeDisposable();

在构造函数中

// hook up the command
var searchCommand = ReactiveCommand.CreateFromTask<TQuery, IEnumerable<TResult>>((query, ct) => DoSearchAsync(query, ct)));
SearchCommand = searchCommand;

// don't forget to subscribe and dispose
searchCommand
    .Subscribe(result => Result = result)
    .DisposeWith(Disposables);