在对话框视图模型的异步加载中捕获异常
本文关键字:加载 捕获异常 异步 对话框 视图 模型 | 更新日期: 2023-09-27 18:28:31
我有一个带有async Task LoadData()
方法的DialogViewModel
类。此方法异步加载数据,并显示此对话框,通知用户有关加载的信息。这是代码:
try
{
var dialog = new DialogViewModel();
var loadTask = dialog.LoadData();
WindowManager.ShowDialog(dialog);
await loadTask;
}
catch (Exception ex)
{
Logger.Error("Error in DialogViewModel", ex);
// Notify user about the error
}
当LoadData
抛出异常时,直到用户退出对话框时才会进行处理。之所以会发生这种情况,是因为在调用await
时会处理异常,而在WindowManager.ShowDialog(dialog)
完成之前不会发生这种情况。
使用异步加载显示对话框的正确方式是什么?我试过这种方法:
- 在
OnShow()
、构造函数或类似程序中调用LoadData()
。但如果我需要在没有任何数据的情况下显示此对话框,这将不起作用 - 显示对话框之前,请致电
await LoadData()
。通过这种方式,用户必须等待数据加载后才能真正看到窗口,但我希望窗口能立即显示加载指示符
为什么有一个显式的公共LoadData
方法?
如果必须发生这种情况,则在构造函数内部使用Task<T>
和ContinueWith
异步执行,以处理通过检查返回任务的IsFaulted
属性生成的任何异常。
这将解决您强调的两个问题。
下面显示了一个非常简单的示例,但您的实现会更加复杂。
public class DialogViewModel
{
private Task _task;
public DialogViewModel()
{
var context = TaskScheduler.FromCurrentSynchronizationContext();
_task = Task.Factory.StartNew(() =>
{
var data = GetDataCollection();
return data;
})
.ContinueWith(t =>
{
if (t.IsFaulted)
{
HasErrored = true;
ErrorMessage = "It's borked!";
}
else
{
Data = t.Result;
}
}, context);
}
public IEnumerable<string> Data { get; private set; }
public bool HasErrored { get; private set; }
public string ErrorMessage { get; private set; }
private static IEnumerable<string> GetDataCollection()
{
return new List<string>()
{
"John",
"Jack",
"Steve"
};
}
}
或者,如果您不想显式使用Task<T>
,而想使用async''await功能,您可以使用稍微不同的方法,因为您不能将async''await与类构造函数一起使用:
public class DialogViewModel
{
public IEnumerable<string> Data { get; private set; }
public bool HasErrored { get; private set; }
public string ErrorMessage { get; private set; }
async public static Task<DialogViewModel> BuildViewModelAsync()
{
try
{
var data = await GetDataCollection();
return new DialogViewModel(data);
}
catch (Exception)
{
return new DialogViewModel("Failed!");
}
}
private DialogViewModel(IEnumerable<string> data)
{
Data = data;
}
private DialogViewModel(string errorMessage)
{
HasErrored = true;
ErrorMessage = errorMessage;
}
private async static Task<IEnumerable<string>> GetDataCollection()
{
// do something async...
return await Task.Factory.StartNew(() => new List<string>()
{
"John",
"Jack",
"Steve"
});
}
}