C# 捕获对话框viewmodel异步加载中的异常
我有一个带有C# 捕获对话框viewmodel异步加载中的异常,c#,wpf,mvvm,dialog,async-await,C#,Wpf,Mvvm,Dialog,Async Await,我有一个带有async Task LoadData()方法的DialogViewModel类。此方法异步加载数据并显示此对话框,通知用户加载。代码如下: try { var dialog = new DialogViewModel(); var loadTask = dialog.LoadData(); WindowManager.ShowDialog(dialog); await loadTask; } catch (Exception ex) { Lo
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
抛出异常时,直到用户退出对话框,才会处理该异常。之所以发生这种情况,是因为调用wait
时处理了异常,并且直到WindowManager.ShowDialog(dialog)
完成后才会发生异常
显示异步加载对话框的正确方式是什么?我试过这样做:
OnShow()
、构造函数或类似程序中调用LoadData()
。但是,如果我需要在没有任何数据的情况下显示此对话框,那么这将不起作用等待LoadData()
。这样,用户在实际看到窗口之前必须等待数据加载,但我希望窗口立即显示一个加载指示器为什么有一个显式的public
LoadData
方法
如果必须这样做,则在构造函数内部使用Task
和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"
};
}
}
公共类对话框视图模型
{
私人任务(u Task),;
公共对话框ViewModel()
{
var context=TaskScheduler.FromCurrentSynchronizationContext();
_task=task.Factory.StartNew(()=>
{
var data=GetDataCollection();
返回数据;
})
.ContinueWith(t=>
{
如果(t.IsFaulted)
{
HasErrored=true;
ErrorMessage=“它是borked!”;
}
其他的
{
数据=t.结果;
}
},上下文);
}
公共IEnumerable数据{get;private set;}
public bool hasrerred{get;private set;}
公共字符串错误消息{get;private set;}
私有静态IEnumerable GetDataCollection()
{
返回新列表()
{
“约翰”,
“杰克”,
“史蒂夫”
};
}
}
或者,如果您不想显式地使用Task
并想使用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"
});
}
}
公共类对话框视图模型
{
公共IEnumerable数据{get;private set;}
public bool hasrerred{get;private set;}
公共字符串错误消息{get;private set;}
异步公共静态任务BuildViewModelAsync()
{
尝试
{
var data=await GetDataCollection();
返回新的DialogViewModel(数据);
}
捕获(例外)
{
返回新的DialogViewModel(“失败!”);
}
}
私有对话框ViewModel(IEnumerable数据)
{
数据=数据;
}
专用对话框ViewModel(字符串错误消息)
{
HasErrored=true;
ErrorMessage=ErrorMessage;
}
私有异步静态任务GetDataCollection()
{
//做一些异步的事情。。。
返回wait Task.Factory.StartNew(()=>newlist())
{
“约翰”,
“杰克”,
“史蒂夫”
});
}
}
不幸的是,这个问题的答案不适合我。我已经写过Show()
。我想需要从外部调用“LoadData()”,因为只有调用者决定是否加载数据。至于“BackgroundWorker”-我希望有一种方法可以通过async await做到这一点,WindowManager.ShowDialog()
来自哪里?是Caliburn Micro吗?是的,但这并不重要:它可以是任何ShowDialog()
实现,例如视图注入。但是LoadData()
将始终被调用,但我可能希望在不加载任何数据的情况下显示此对话框(如我在第一种情况中所述)。好吧,这就是我认为您有问题的地方,要么永远叫它,要么永远不叫它。因为否则它在什么时候应该被称为。。。