当我单击导致LoginCommand
启动的"登录"按钮时,我有一些长时间运行的任务正在执行。
我也通过调用LoginCommand.Execute()
在ViewModel的OnAppearing
中调用此LoginCommand
。为了实现这一点,我想最好调用一些函数。有没有一种更清洁的好方法?
这是我的LoginViewModel
上的内容,它是从BaseViewModel
派生而来的。我的BasePage
调用OnAppearing
public class BaseViewModel : INotifyPropertyChanged
{
public virtual void OnAppearing() { }
}
public class LoginViewModel: BaseViewModel
{
public override void OnAppearing() {
// is there a better way than calling the LoginCommand itself?
LoginCommand.Execute(this);
}
public ICommand LoginCommand
{
get
{
return new Command(async () =>
{
var validationResult = await SomeLongRunningValidation();
if (!validationResult.Authenticated)
{
await navigation.DisplayAlert("Error", "Authentication failed. Try again?", "Yes", "No");
}
});
}
}
}
评论中的建议是准确的。
首先提取命令处理程序中的代码,并将其封装到自己的异步方法中。让命令处理程序在调用时调用它。提取的方法也可以从其他方法(如OnAppearing
)中调用。为了避免阻塞,您希望保持代码异步。您可以创建一个异步事件处理程序来处理在引发事件时调用异步方法。
public class LoginViewModel: BaseViewModel {
private event EventHandler Appearing = delegate { };
public override void OnAppearing() {
EventHandler handler = null;
handler = async (sender, e) => {
Appearing -= handler; //Unsubscribe from event
await LoginAsync(); // non-blocking async call
};
Appearing += handler;//Subscribe to event
Appearing(this, EventArgs.Empty);//raise event
}
private ICommand loginCommand = new Command(async () => {
await LoginAsync();//non-blocking async call
});
public ICommand LoginCommand {
get {
return loginCommand;
}
}
private async Task LoginAsync() {
var validationResult = await SomeLongRunningValidation();
if (!validationResult.Authenticated) {
await navigation.DisplayAlert("Error", "Authentication failed. Try again?", "Yes", "No");
}
}
}
没有代表的版本
public class LoginViewModel: BaseViewModel {
public LoginViewModel() : base() {
Appearing += handler;//Subscribe to event
}
private event EventHandler Appearing = delegate { };
private async void handler(object sender, EventArgs e) {
Appearing -= handler; //Unsubscribe from event
await LoginAsync(); // non-blocking async call
}
public override void OnAppearing() {
Appearing(this, EventArgs.Empty);//raise event
}
private ICommand loginCommand = new Command(async () => {
await LoginAsync();//non-blocking async call
});
public ICommand LoginCommand {
get {
return loginCommand;
}
}
private async Task LoginAsync() {
var validationResult = await SomeLongRunningValidation();
if (!validationResult.Authenticated) {
await navigation.DisplayAlert("Error", "Authentication failed. Try again?", "Yes", "No");
}
}
}