【发布时间】:2017-08-08 22:28:03
【问题描述】:
我正在使用 MVVM Light 并且有一个接口 IDialogService 用于显示对话框。该接口已在 App.xaml.cs 中实现
一个具体的方法很有趣:
Task<bool> ShowMessage(string message, string title, string buttonConfirmText, string buttonCancelText, Action<bool> afterHideCallback);
方法实现为:
public Task<bool> ShowMessage(string message, string title, string buttonConfirmText,
string buttonCancelText,
Action<bool> afterHideCallback)
{
return Task.Factory.StartNew(() =>
{
var style = new Style(typeof(MessageBox));
style.Setters.Add(new Setter(MessageBox.OkButtonContentProperty, buttonConfirmText));
style.Setters.Add(new Setter(MessageBox.CancelButtonContentProperty, buttonCancelText));
var result = MessageBox.Show(_GetActiveWindow(), message, title,
MessageBoxButton.OKCancel,
MessageBoxImage.Question, style) == MessageBoxResult.OK;
if (afterHideCallback != null) afterHideCallback(result);
return result;
_currentTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 在 OnStartup 中定义
所以通常我们应该在调用这个方法前加上await来获取布尔值:
var result = await DialogService.ShowMessage(
Resources.Areyousure,Resources.Warning,
Resources.Yes, Resources.No, null);
到目前为止一切顺利。现在我有一个包装方法来执行代码并捕获异常,然后显示带有错误的消息框。
public bool TryCatchExecution(Action action, string successMessage = null)
{
try
{
action();
if (!string.IsNullOrEmpty(successMessage))
DialogService.ShowMessage(successMessage, Resources.Success);
return true;
}
catch (LogException ex)
{
DialogService.ShowError(ex.Error.LogMessage, Resources.Error, Resources.OK, null);
}
catch (Exception ex)
{
DialogService.ShowError(ex.Message, Resources.Error, Resources.OK, null);
}
return false;
}
现在我有一个问题。如果我使用样例 A,则 GUI 线程在 var result = DialogService.ShowMessage 行被阻塞。但是,如果我在示例 B 中使用 GUI 线程,则未阻塞,显示消息框,并且一切正常。直到我得到一个例外。异常没有被代码处理。错误是“在 mscorlib.dll 中发生了‘System.ServiceModel.FaultException`1’类型的第一次机会异常”并且应用程序崩溃。正如我一直在阅读的,这与 SynchronizationContext 有关。
//Sample A
private void ExecuteDeleteCommand()
{
TryCatchExecution(() =>
{
var result = DialogService.ShowMessage(
Resources.Areyousure,
Resources.Warning,
Resources.Yes,
Resources.No, null).Result;
if (!result) return;
_datalayer.DeleteField(FieldSelected);
Refresh();
FieldEdit = new MsgSqlFieldMapping();
RaisePropertyChanged("SqlRepository");
DialogService.ShowMessage(Resources.OperationSucceeded, Resources.Success);
});
}
//Sample B
private void ExecuteDeleteCommand()
{
TryCatchExecution(async () =>
{
var result =await DialogService.ShowMessage(
Resources.Areyousure,
Resources.Warning,
Resources.Yes,
Resources.No, null);
if (!result) return;
_datalayer.DeleteField(FieldSelected);
Refresh();
FieldEdit = new MsgSqlFieldMapping();
RaisePropertyChanged("SqlRepository");
await DialogService.ShowMessage(Resources.OperationSucceeded, Resources.Success);
});
}
请帮助我了解这里发生了什么以及如何处理它。
THNX 很多。
【问题讨论】:
-
我忘了说我使用的是.net4.5框架。
标签: c# wpf async-await task ui-thread