从 IActivatableViewModel 中的 WhenActivated 调用异步方法
Call async method from WhenActivated in IActivatableViewModel
我正在使用 AvaloniaUI 框架构建应用程序。
我有一个实现 IActivatableViewModel
的视图模型,我在视图模型构造函数中调用 WhenActivated
。我定义了一个方法 HandleActivation
,当视图模型被激活时调用,当视图模型被停用时调用 HandleDeactivation
。一切都被正确调用,那里没有问题。
看起来像这样:
public abstract class MyViewModel: ViewModelBase, IActivatableViewModel
{
public ViewModelActivator Activator { get; }
protected MyViewModel() : base()
{
Activator = new ViewModelActivator();
this.WhenActivated(disposables =>
{
this.HandleActivation();
Disposable
.Create(this.HandleDeactivation)
.DisposeWith(disposables);
});
}
private void HandleActivation()
{ }
private void HandleDeactivation()
{ }
}
我还有一个数据服务,可以从数据库中检索一些数据。我要调用的方法returns一个Task<T>
。
它看起来像这样:
public interface IDataService
{
Task<IList<UserDto>> GetActiveUsers();
}
我想做的是从 HandleActivation 方法调用 GetActiveUsers
。我需要获取用户列表,然后在检索到用户后对其进行一些 post 处理。
如果我在异步方法中这样做,我会做这样的事情
private async Task HandleActivation()
{
var users = await _dataService.GetActiveUsers();
foreach(var user in users)
{
//do stuff
}
}
由于 HandleActivation
不是异步方法,我对如何去做这件事有点困惑。
有没有一种方法可以使 HandleActivation
异步,是否有一种我缺少的“反应式”方法。
我对 AvaloniaUI 和 ReactiveUI 以及反应式编程本身还很陌生,所以我确信有一种“正确”的方法可以做到这一点,但我很难弄明白。
第一个代码片段中关于处理激活和停用的模式与 ReactiveUI 文档中的示例相匹配,但是没有人阻止您将 HandleActivation 方法编写为异步的,因此它看起来像这样:
protected MyViewModel() : base()
{
Activator = new ViewModelActivator();
this.WhenActivated(disposables =>
{
this.HandleActivation().ConfigureAwait(false);
Disposable
.Create(this.HandleDeactivation)
.DisposeWith(disposables);
});
}
private async Task HandleActivation()
{
var users = await Task<IEnumerable<UserDto>>.Factory.StartNew(() => _dataService.GetActiveUsers().Result);
foreach (var user in users)
{
// do stuff
}
}
使用可观察对象的更具反应性的方法可能如下所示:
protected MyViewModel() : base()
{
Activator = new ViewModelActivator();
this.WhenActivated(disposables =>
{
this.HandleActivation();
Disposable
.Create(this.HandleDeactivation)
.DisposeWith(disposables);
});
}
private void HandleActivation()
{
Observable.Start(() => _dataService.GetActiveUsers().Result)
.ObserveOn(RxApp.MainThreadScheduler) // schedule back to main scheduler only if the 'stuff to do' is on ui thread
.Subscribe(users => DoStuffWithTheUsers(users));
}
private void DoStuffWithTheUsers(IEnumerable<UserDto> users)
{
foreach (var user in users)
{
// do stuff
}
}
如果 GetActiveUsers 本身是返回 IList 的同步方法,这甚至可以异步工作,因为 Observable.Start 已经异步调用了该方法。代码示例中的唯一区别是必须删除“.Result”。
处理此类模式的另一种选择是使用 ReactiveCommand<Unit, Unit>
。响应式命令很棒,它们让你在管理 long-running 异步操作方面拥有超强的能力。一个reactive command allows you to subscribe to the IsExecuting
and ThrownExceptions
observables and keep your users informed about what your app is doing. Also, reactive commands support cancelation。所以我可能建议你将激活逻辑移动到一个反应命令中,例如命名为Activate
,将停用逻辑移动到名为 Deactivate
的响应式命令中,然后在 WhenActivated
块内,您可以这样做:
this.WhenActivated(disposable => {
Activate.Execute().Subscribe(); // Handle async activation
Disposable
.Create(() => Deactivate.Execute().Subscribe()) // Handle async deactivation
.DisposeWith(disposable);
});
另见 。
我正在使用 AvaloniaUI 框架构建应用程序。
我有一个实现 IActivatableViewModel
的视图模型,我在视图模型构造函数中调用 WhenActivated
。我定义了一个方法 HandleActivation
,当视图模型被激活时调用,当视图模型被停用时调用 HandleDeactivation
。一切都被正确调用,那里没有问题。
看起来像这样:
public abstract class MyViewModel: ViewModelBase, IActivatableViewModel
{
public ViewModelActivator Activator { get; }
protected MyViewModel() : base()
{
Activator = new ViewModelActivator();
this.WhenActivated(disposables =>
{
this.HandleActivation();
Disposable
.Create(this.HandleDeactivation)
.DisposeWith(disposables);
});
}
private void HandleActivation()
{ }
private void HandleDeactivation()
{ }
}
我还有一个数据服务,可以从数据库中检索一些数据。我要调用的方法returns一个Task<T>
。
它看起来像这样:
public interface IDataService
{
Task<IList<UserDto>> GetActiveUsers();
}
我想做的是从 HandleActivation 方法调用 GetActiveUsers
。我需要获取用户列表,然后在检索到用户后对其进行一些 post 处理。
如果我在异步方法中这样做,我会做这样的事情
private async Task HandleActivation()
{
var users = await _dataService.GetActiveUsers();
foreach(var user in users)
{
//do stuff
}
}
由于 HandleActivation
不是异步方法,我对如何去做这件事有点困惑。
有没有一种方法可以使 HandleActivation
异步,是否有一种我缺少的“反应式”方法。
我对 AvaloniaUI 和 ReactiveUI 以及反应式编程本身还很陌生,所以我确信有一种“正确”的方法可以做到这一点,但我很难弄明白。
第一个代码片段中关于处理激活和停用的模式与 ReactiveUI 文档中的示例相匹配,但是没有人阻止您将 HandleActivation 方法编写为异步的,因此它看起来像这样:
protected MyViewModel() : base()
{
Activator = new ViewModelActivator();
this.WhenActivated(disposables =>
{
this.HandleActivation().ConfigureAwait(false);
Disposable
.Create(this.HandleDeactivation)
.DisposeWith(disposables);
});
}
private async Task HandleActivation()
{
var users = await Task<IEnumerable<UserDto>>.Factory.StartNew(() => _dataService.GetActiveUsers().Result);
foreach (var user in users)
{
// do stuff
}
}
使用可观察对象的更具反应性的方法可能如下所示:
protected MyViewModel() : base()
{
Activator = new ViewModelActivator();
this.WhenActivated(disposables =>
{
this.HandleActivation();
Disposable
.Create(this.HandleDeactivation)
.DisposeWith(disposables);
});
}
private void HandleActivation()
{
Observable.Start(() => _dataService.GetActiveUsers().Result)
.ObserveOn(RxApp.MainThreadScheduler) // schedule back to main scheduler only if the 'stuff to do' is on ui thread
.Subscribe(users => DoStuffWithTheUsers(users));
}
private void DoStuffWithTheUsers(IEnumerable<UserDto> users)
{
foreach (var user in users)
{
// do stuff
}
}
如果 GetActiveUsers 本身是返回 IList 的同步方法,这甚至可以异步工作,因为 Observable.Start 已经异步调用了该方法。代码示例中的唯一区别是必须删除“.Result”。
处理此类模式的另一种选择是使用 ReactiveCommand<Unit, Unit>
。响应式命令很棒,它们让你在管理 long-running 异步操作方面拥有超强的能力。一个reactive command allows you to subscribe to the IsExecuting
and ThrownExceptions
observables and keep your users informed about what your app is doing. Also, reactive commands support cancelation。所以我可能建议你将激活逻辑移动到一个反应命令中,例如命名为Activate
,将停用逻辑移动到名为 Deactivate
的响应式命令中,然后在 WhenActivated
块内,您可以这样做:
this.WhenActivated(disposable => {
Activate.Execute().Subscribe(); // Handle async activation
Disposable
.Create(() => Deactivate.Execute().Subscribe()) // Handle async deactivation
.DisposeWith(disposable);
});
另见