我正在使用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
的位置
所以通常我们应该在前面等待调用此方法来获取布尔值:
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线程未被阻止,则显示消息框,并且一切正常。直到我得到一个例外。代码无需例外。错误是&#34;类型&#39; System.ServiceModel.FaultException`1&#39;的第一次机会异常。发生在mscorlib.dll&#34;和应用程序崩溃。正如我一直在阅读这与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很多。
答案 0 :(得分:1)
您的问题归因于async void
- 具体而言,通过将async
lambda作为Action
类型的参数传递,您正在创建async void
方法。其中一个problems with async void
methods是你无法捕捉异常(至少不是正常的方式)。
要解决此问题,请创建一个带有async equivalent of Action
, which is Func<Task>
:
public async Task<bool> TryCatchExecution(Func<Task> action, string successMessage = null)
{
try
{
await 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;
}