如何使用 ReactiveUI 正确取消 ViewModel 停用任务? [英] How to properly cancel a Task on ViewModel-deactivation with ReactiveUI?

查看:31
本文介绍了如何使用 ReactiveUI 正确取消 ViewModel 停用任务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的 MVVM 应用程序中,当 ViewModel 被激活时,会启动一个任务,该任务建立网络连接并且可能需要一些时间才能完成.此任务可取消:

In my MVVM application, when a ViewModel gets activated, a Task gets started that establishes a network connection and could take some time to complete. This Task is cancalable:

private async Task ConnectAsync(CancellationToken cancellationToken = default)
{
    ...
}

我正在使用 IActivatableViewModel 在 ViewModel-activation 上启动它:

I'm using IActivatableViewModel to start it on ViewModel-activation like that:

// Constructor:
public SomeViewModel(...)
{
    this.WhenActivated(disposable => {
        Observable.StartAsync(ConnectAsync);
    });
}

现在,当 ViewModel 在 Task 完成之前被停用时,取消这个长时间运行的 Task 的推荐方法是什么?

Now what is the recommended method to cancel this long-running Task when the ViewModel gets deactivated before the Task completes?

我想出了这个:

this.WhenActivated(disposable => {
    Observable.StartAsync(ConnectAsync).Subscribe().DisposeWith(disposable);
});

这是正确的解决方案还是有更好的解决方案?

Is this the right solution or is there a better one?

先谢谢你!

推荐答案

是的,您在代码片段中显示的代码看起来不错.但是,可能值得将 ConnectAsync 方法调用移动到 ReactiveCommand (文档).如果您这样做,您将获得诸如订阅 ThrownExceptionsIsExecuting observables 之类的特权,然后显示一些加载指示器或错误消息,让您的用户了解什么该应用程序正在做.此外,按照此处描述的模式,您可以通过另一个命令或事件取消该 ReactiveCommand.通过事件取消看起来像这样:

Yeah, the code like you show in your code snippet looks good. However, probably worth moving the ConnectAsync method call to a ReactiveCommand<TInput, TOutput> (docs). If you do this, you get such perks as the ability to subscribe to ThrownExceptions and IsExecuting observables, and then display some loading indicators or error messages to keep your users informed about what the app is doing. Also, following the pattern described here, you can cancel that ReactiveCommand<TInput, TOutput> via another command or event. Cancelation via an event would look like this:

// ViewModel.cs
Cancel = ReactiveCommand.Create(() => { });
Connect = ReactiveCommand
    .CreateFromObservable(
        () => Observable
            .StartAsync(ConnectAsync)
            .TakeUntil(Cancel));

// View.xaml.cs
this.WhenActivated(disposable => {
    this.Events() // Launch the long-running operation
        .Loaded
        .Select(args => Unit.Default)
        .InvokeCommand(ViewModel, x => x.Connect)
        .DisposeWith(disposable);
    this.Events() // Stop that long-running operation
        .Unloaded
        .Select(args => Unit.Default)
        .InvokeCommand(ViewModel, x => x.Cancel)
        .DisposeWith(disposable);
});

这里,我假设 ConnectAsync 是一种接受取消令牌并返回 Task 的方法.为了启用 this.Events() 魔法,您需要使用 Pharmacist,或安装 ReactiveUI.Events 包之一.但无论如何,如果您想依赖 WhenActivated,不需要 ThrownExceptionsIsExecuting 等,那么您的选择看起来也不错.喜欢使用命令,依赖WhenActivated,然后修改View.xaml.cs代码:

Here, I assume ConnectAsync is a method accepting a cancelation token and returning a Task. In order to enable the this.Events() magic, you need to either use Pharmacist, or to install one of the ReactiveUI.Events packages. But anyway, your option looks good as well if you want to rely on WhenActivated, don't need ThrownExceptions, IsExecuting etc. If you'd like to use commands and rely on WhenActivated, then modify the View.xaml.cs code:

// View.xaml.cs
this.WhenActivated(disposable => {
    Connect.Execute().Subscribe();
    Disposable
        .Create(() => Cancel.Execute().Subscribe())
        .DisposeWith(disposable);
});

我们不会处理由 Execute() 返回的订阅,因为它们会在命令完成执行时被处理.希望这可以帮助!✨

We aren't disposing of the subscriptions returned by Execute() because they'll get disposed anyway when the commands complete their execution. Hope this helps! ✨

这篇关于如何使用 ReactiveUI 正确取消 ViewModel 停用任务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆