使用“X”按钮或 ESC 键关闭 WPF 窗口时的确认
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19589462/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Confirmation when closing WPF window with 'X' button or ESC-key
提问by ofodjs
How can I request confirmation when closing WPF window in desktop application with click 'X' button or by pressing ESC-key?
I would like to make it with a minimum of code.
Similar issue is herebut on MVVM Light and there is too much code.
在通过单击“X”按钮或按 ESC 键关闭桌面应用程序中的 WPF 窗口时,如何请求确认?
我想用最少的代码来制作它。
类似的问题在这里,但在 MVVM Light 上,代码太多。
采纳答案by ofodjs
AI found IMHO nice solutionwith Attached Behavior. The addition of this functionality is to add only one namespace and one attribute to window-tag:
AI 发现带有附加行为的恕我直言不错的解决方案。这个功能的增加是只为window-tag添加一个命名空间和一个属性:
MainWindow.xaml
主窗口.xaml
<Window x:Class="WpfClosingByEscape.MainWindow"
...
xmlns:bhv="clr-namespace:WpfClosingByEscape.Behaviors"
bhv:WindowClosingBehavior.Enabled="True"
>
...
</Window>
Everything else in the behavior-class:
行为类中的其他所有内容:
private static void OnValueChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is Window))
{
return;
}
var window = d as Window;
if ((bool)e.NewValue)
{
InputBinding escapeBinding = new InputBinding(AppCommands.WindowCloseCommand, new KeyGesture(Key.Escape));
escapeBinding.CommandParameter = window;
window.InputBindings.Add(escapeBinding);
window.Closing += Window_Closing;
}
else
{
window.Closing -= Window_Closing;
}
}
static void Window_Closing(object sender, CancelEventArgs e)
{
#if DEBUG
#else
e.Cancel = MessageBox.Show(window, "Are you sure?", "Exit",
MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.Yes;
#endif
}
回答by Mike Perrenoud
Leverage the OnClosingvirtual method:
利用OnClosing虚方法:
protected override void OnClosing(CancelEventArgs e)
{
// show the message box here and collect the result
// if you want to stop it, set e.Cancel = true
e.Cancel = true;
}
That internal code might look like this:
该内部代码可能如下所示:
var result = MessageBox.Show(...);
if (result == DialogResult.{SomeEnumVal}) { e.Cancel = true; }
回答by Matt Becker
I was looking for a more MVVM way of doing it. So here's what worked for me.
我正在寻找一种更 MVVM 的方式来做这件事。所以这对我有用。
The Window code
窗口代码
<Window x:Class="My.Namespace.Wpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
mc:Ignorable="d"
Closing="Window_Closing">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<i:InvokeCommandAction Command="{Binding ExitApplicationCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
The code behind
背后的代码
/// <summary>
/// Handles the Closing event of the Window control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.ComponentModel.CancelEventArgs"/> instance containing the event data.</param>
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = !_viewModel.ShouldCloseApp;
}
The command in the view model
视图模型中的命令
public bool ShouldCloseApp { get; private set; }
private RelayCommand<Window> _exitApplicationCommand;
public RelayCommand<Window> ExitApplicationCommand
{
get
{
if (_exitApplicationCommand == null)
{
_exitApplicationCommand = new RelayCommand<Window>(exitApplicationCommand);
}
return _exitApplicationCommand;
}
}
/// <summary>
/// This closes a specified window. If you pass the main window, then this application
/// will exit. This is because the application shut down mode is set to OnMainWindowClose.
/// </summary>
/// <param name="window">The window to close.</param>
private void exitApplicationCommand(Window window)
{
try
{
DialogService.ShowConfirmation(
UIStrings.MainWindowViewModel_ExitProgramHeader,
UIStrings.MainWindowViewModel_ExitProgramMessage,
UIStrings.MainWindowViewModel_ExitProgramAcceptText,
UIStrings.MainWindowViewModel_ExitProgramCancelText,
(DialogResult result) =>
{
if ((result.Result.HasValue) && (result.Result.Value))
{
if (ElectroTekManager.Manager.ConnectedElectroTek != null)
{
SendToStatusOperation operation = new SendToStatusOperation(ElectroTekManager.Manager.ConnectedElectroTek, (operationResult, errorMessage) =>
{
if (operationResult != FirmwareOperation.OperationResult.Success)
{
log.Debug(string.Format("{0} {1}", CautionStrings.MainWindowViewModel_LogMsg_UnableToSendToStatus, errorMessage));
}
else if (!string.IsNullOrEmpty(errorMessage))
{
log.Debug(errorMessage);
}
Application.Current.Dispatcher.Invoke(new Action(() => closeApp(window)));
});
operation.Execute();
}
else
{
closeApp(window);
}
}
});
}
catch (Exception ex)
{
log.Debug(CautionStrings.MainWindowViewModel_LogMsg_FailedToShowConfirmation, ex);
}
}
/// <summary>
/// Closes the application.
/// </summary>
/// <param name="window">The window.</param>
private void closeApp(Window window)
{
ShouldCloseApp = true;
Dispose();
Application.Current.Shutdown();
}
After the confirmation, I call Application.Current.Shutdown(). This triggers the closing event in the code behind a second time, but will not trigger the exit command again.
确认后,我调用Application.Current.Shutdown()。这会第二次触发后面代码中的关闭事件,但不会再次触发退出命令。

