问题描述
我正在使用AvaloniaUI框架来构建应用程序。
我有一个实现IActivatableviewmodel
的viewmodel,并在viewmodel构造函数中调用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()
{ }
}
我还有一个数据服务,可以从数据库中检索一些数据。我要调用的方法返回一个Task<T>
。
看起来像这样:
public interface IDataService
{
Task<IList<UserDto>> GetActiveUsers();
}
我想做的是从HandleActivation方法中调用GetActiveUsers
。我需要获取用户列表,然后在检索用户后对其进行一些后处理。
如果我使用异步方法执行此操作,那么我会执行类似的操作
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”。
,处理此类模式的另一种方法是使用Boolean
。反应性命令很棒,它们使您能够管理长时间运行的异步操作。 reactive command允许您订阅bool[] boolArray = {false,true,false,false};
newTile = new Tile(1,3,1,12,-1,boolArray,-1);
和ReactiveCommand<Unit,Unit>
的观察对象,并让用户知道您的应用程序在做什么。另外,反应式命令支持cancelation。因此,我可能建议您将激活逻辑移至名为例如IsExecuting
,将停用逻辑转移到名为ThrownExceptions
的反应式命令中,然后在Activate
块中,您可以执行以下操作:
Deactivate