使用ReactiveUI进行火灾并忘记

时间:2014-10-18 03:12:18

标签: c# reactiveui

我目前正在玩ReactiveUI(有一些Rx之前的经验)。 我正在尝试做的是处理某种火灾/忘记/通知工作流程。

基本上,我想执行和操作,然后在成功或失败时收到通知。但是,在执行下一个操作之前,我不想等待该操作完成,因此我实现了以下代码片段:

    private ReactiveList<VerifiableString> _inputData = new ReactiveList<VerifiableString>();
    private ReactiveList<VerifiableString> _savedData = new ReactiveList<VerifiableString>();

    private Subject<VerifiableString> _stringSubject = new Subject<VerifiableString>();

    private ReactiveCommand<Unit> _addCommand;

    public MainViewModel()
    {
        for (int i = 0; i < 10; i++)
        {
            _inputData.Add(new VerifiableString{Value = Guid.NewGuid().ToString()});
        }

        var canExecute = this.WhenAny(x => x.InputData.Count, x => x.Value != 0);

        AddCommand = ReactiveCommand.CreateAsyncTask(canExecute, x => SendStringForProcessingAsync());
        AddCommand.ThrownExceptions.Subscribe(ex => MessageBox.Show(ex.ToString()));

        _stringSubject.ObserveOn(RxApp.MainThreadScheduler).Subscribe(AddString, e => MessageBox.Show(e.Message));
    }

    private async Task<Unit> SendStringForProcessingAsync()
    {
        var item = InputData.First();
        InputData.RemoveAt(0);
        //intentionally not awaiting on this
        PostNewItemAsync(item);
        return new Unit();
    }

    private async Task PostNewItemAsync(VerifiableString item)
    {
        _stringSubject.OnNext(item);
        await Task.Delay(1000);
        item.Verified = true;
        _stringSubject.OnNext(item);
    }

此代码按我的预期工作。我可以根据需要多次调用该命令,获得调用该命令的即时通知,然后1s后,通知该命令已完成。

我有一种感觉,通过使用ReactiveCommand和Subject,我可能会忽略ReactiveUI的观点?此外,通过使用主题,我没有得到你直接使用ReactiveCommands可以观察到的那个可爱的ThrownError。

对于上下文,UI包含两个列表和一个按钮,单击该按钮可将字符串从一个列表移动到另一个列表,稍后,该字符串将使用“已验证”标志进行更新。

EDIT 20141023

现在我有了这个:

{
    //...
    AddCommand
       .SelectMany(_ => Observable.FromAsync(SendStringForProcessingAsync))
       .Catch(Observable.Return(new VerifiableString{Value = "What the hell !"}))
       .ObserveOn(RxApp.MainThreadScheduler)
       .Subscribe(AddString);

    AddCommand.ThrownExceptions.Subscribe(ex => Debug.WriteLine(ex));
    //...
}

private async Task<VerifiableString> PostNewItemAsync(VerifiableString param, CancellationToken cancellationToken)
{
    await Task.Delay(_random.Next(1000, 5000), cancellationToken);
    param.Verified = VerifyState.Verified;
    return param;
}


private async Task<VerifiableString> SendStringForProcessingAsync(CancellationToken t)
{
    var item = InputData.First();
    InputData.RemoveAt(0);
    AddString(item);
    return await PostNewItemAsync(item, t);
}

如果我在“SendStringForProcessingAsync”中抛出异常,我的“错误消息”会出现在我的列表中(尽管调试日志中没有任何内容)。但是,此时,我再也无法继续执行命令。

另外,我使用了Observable.FromAsync,因此我可以传递取消令牌,并取消飞行中的物品。我不能为我的生活,弄清楚如何访问CancellationTokenSource所以我可以取消这些东西......

我错过了一些明显的东西吗?

1 个答案:

答案 0 :(得分:1)

如果您想退出RxCmd的单项内容,您可以执行以下操作(因为编码通过TextArea而遗漏了正确的泛型):

AddCommand = ReactiveCommand.Create();

AddCommand
    .SelectMany(_ => DoSomethingAsync()
        .Catch(ex => { log.write("Crap."); return Observable.Empty(); }))
    .Subscribe(x => log.write("It worked!");