我从父表单启动了一个子表单,其中包含:
ConfigForm cfg = new ConfigForm();
cfg.ShowDialog();
此子窗体用于配置某些应用程序参数。 我想检查是否有一些未保存的更改,如果是,请警告用户。 所以我的On OnClosing事件以这种方式声明:
private async void ChildFormClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
// Here i call a function that compare the current config with the saved config
bool isUptated = CheckUnsavedChanges();
// If updated is false, it means that there are unsaved changes...
if (!isUpdated)
{
e.Cancel = true;
// At this point i create a MessageDialog (Mahapps) to warn the user about unsaved changes...
MessageDialogStyle style = MessageDialogStyle.AffirmativeAndNegative;
var metroDialogSettings = new MetroDialogSettings()
{
AffirmativeButtonText = "Close",
NegativeButtonText = "Cancel"
};
var result = await this.ShowMessageAsync("Config", "There are unsaved changes, do you want to exit?", style, metroDialogSettings);
// If we press Close, we want to close child form and go back to parent...
if (result == MessageDialogResult.Affirmative)
{
e.Cancel = false;
}
}
}
我的逻辑说,如果我将e.cancel声明为false,它将继续关闭表单,但不会发生,子表单仍然打开。
我的猜测是异步调用正在做一些我不理解的事情,因为如果我以这种方式声明ChildFormClosing:
private async void ChildFormClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
bool isUptated = CheckUnsavedChanges();
e.Cancel = true;
if (!isUpdated)
{
MessageDialogStyle style = MessageDialogStyle.AffirmativeAndNegative;
var metroDialogSettings = new MetroDialogSettings()
{
AffirmativeButtonText = "Close",
NegativeButtonText = "Cancel"
};
var result = await this.ShowMessageAsync("Config", "There are unsaved changes, do you want to exit?", style, metroDialogSettings);
if (result == MessageDialogResult.Affirmative)
{
e.Cancel = false;
}
}
else
{
e.Cancel = false;
}
}
最后的其他e.Cancel = false工作,子表单已关闭...
有任何线索吗? 谢谢!
答案 0 :(得分:4)
由于此方法是窗口的事件处理程序,因此它将在UI线程上调用,因此不需要异步显示消息框。
至于您所看到的奇怪行为,这与事件处理程序中的await
有关。当您await
进行方法调用时,实际发生的事情是await
之前的所有内容都正常执行,但一旦await
语句达到控制权,控制权就会返回给调用者。一旦await
的方法返回,则执行原始方法的其余部分。
触发OnClosing
事件的代码可能不是为异步事件处理程序设计的,因此它假设如果事件处理程序返回,它已完成它需要做的任何工作。由于您的事件处理程序在方法调用CancelEventArgs.Cancel
之前将true
设置为await
,因此事件处理程序的调用方看到它设置为true
,因此它不会#39;关闭表格。
这就是显示消息框同步工作的原因:整个方法在控制权返回给调用者之前执行,因此CancelEventArgs.Cancel
始终设置为其预期值。
Raymond Chen最近发表了两篇关于async
可能有趣的文章:Crash course in async and await和The perils of async void。第二篇文章描述了为什么async
事件处理程序往往不按预期方式工作。