我有一个涉及数据库的应用程序。以前,在打开窗口时,我会查询数据库并使用它来填充 View 模型的各个方面。这工作得相当好,但当数据访问时间比预期长时可能会造成明显的暂停。
当然,自然的解决方案是异步运行数据库查询,然后在查询完成时填充 View 模型。这并不太难,但它提出了一些有关错误处理的有趣问题。
以前,如果数据库查询出现问题(这是一个相当大的问题,当然),我会通过 View 模型构造函数传播异常,最终将其返回给想要打开窗口的调用者。然后它可能会显示适当的错误,但实际上不会打开窗口。
但是现在,窗口会立即打开,然后在查询完成后填充。现在的问题是,我应该在什么时候检查后台任务中的错误?窗口已经打开,因此行为需要以某种方式有所不同,但是向用户指示失败并允许正常恢复/关闭的干净方法是什么?
作为引用,这里是演示基本模式的片段:
public ViewModel()
{
_initTask = InitAsync();
//Now where do I check on the status of the init task?
}
private async Task InitAsync()
{
//Do stuff...
}
//....
public void ShowWindow()
{
var vm = new ViewModel(); //Previously this could throw an exception that would prevent window from being shown
_windowServices.Show(vm);
}
我考虑过的一个选项是使用异步工厂方法来构造 ViewModel,允许在尝试显示窗口之前构造和初始化整个事物。这保留了在窗口打开之前报告错误的旧方法。然而,它放弃了通过这种方法获得的一些 UI 响应能力,这允许窗口的初始加载与查询并行发生,并且还允许我(在某些情况下)在每个查询完成时增量更新 UI,而不是而不是让 UI 立即自行组合。它避免了锁定 UI 线程,但并没有减少用户实际看到窗口并开始与其交互之前的时间。
最佳答案
也许在你的 View 模型和底层服务之间使用某种消息传递/中介?
使用MVVMLight的半伪代码
public ViewModel()
{
Messenger.Default.Register<NotificationMessage<Exception>>(this, message =>
{
// Handle here
});
Task.Factory.StartNew(() => FetchData());
}
public async Task FetchData()
{
// Some magic happens here
try
{
Thread.Sleep(2000);
throw new ArgumentException();
}
catch (Exception e)
{
Messenger.Default.Send(new NotificationMessage<Exception>(this, e, "Aw snap!"));
}
}
关于c# - 异步数据加载及后续错误处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22052507/