[I tagged Catel, but I think this question would apply to any MVVM framework.]
There are several suggestions on this website for handling the Close event (especially from the "red X" button) whereby the programmer wants to check to see if the app can be closed or to display an "Are you sure?" dialog box. I've tried three -- handling the event totally in the View, using event triggers to invoke a command on the ViewModel from XAML, and having the View connect the event handling to a ViewModel event handler. All three ways will trigger when the user tries to close the Window, as expected.
My problem is that if I try to display a MessageBox in the event handler to get confirmation from the User, I get the following exception:
System.InvalidOperationException was unhandled
Message: An unhandled exception of type 'System.InvalidOperationException' occurred in PresentationFramework.dll
Additional information: Cannot set Visibility to Visible or call Show, ShowDialog, Close, or WindowInteropHelper.EnsureHandle while a Window is closing.
The Window that is closing is my main window, so if it closes, so does my app. I know I can cancel the Window's closing by setting the CancelEventArgs.Cancel value to true.
How can I both trap the Closing event and then have my handler determine whether to actually close or not, based on input from the User?
If you need more information, please let me know. Thanks!
Edit: Here's what I'm using to handle the Exit Application menu command:
private async void OnExitApplicationExecute()
if (this.IsProcessing)
{
await this._messageService.ShowWarningAsync("Please click on 'Stop Processing' before closing the Processor.", "Stop Processing First");
}
else
{
MessageResult msgResult = await this._messageService.ShowAsync("Exiting the Processor will halt all request processing." + Environment.NewLine + "Are you sure?",
"Exiting Processor...", MessageButton.YesNo, MessageImage.Question);
if (msgResult == MessageResult.Yes)
{
_logger.Info("Main Task: Application ended.");
this._navigationService.CloseApplication();
}
}
}
The messageService and navigationService calls are Catel services/methods. logger is NLog.
This works when run as a command handler because the Window isn't closing until all checks are complete. If I try to inject this same logic as part of the Closing event handling, I get the exception mentioned above.
Here's part of the stack trace:
2017-11-01 14:45:57.3269 [00009] ERROR App: An unhandled exception occurred and has been logged. Please contact support. System.InvalidOperationException: Cannot set Visibility to Visible or call Show, ShowDialog, Close, or WindowInteropHelper.EnsureHandle while a Window is closing.
at System.Windows.Window.VerifyNotClosing()
at System.Windows.Window.InternalClose(Boolean shutdown, Boolean ignoreCancel)
at System.Windows.Window.Close()
at Catel.Windows.DataWindow.SetDialogResultAndMakeSureWindowGetsClosed(Nullable`1 result) in C:\CI_WS\Ws\105284\Source\Catel\src\Catel.MVVM\Catel.MVVM.Shared\Windows\Windows\DataWindow\DataWindow.cs:line 708
at Catel.Windows.DataWindow.<OnDataWindowClosing>b__104_0() in C:\CI_WS\Ws\105284\Source\Catel\src\Catel.MVVM\Catel.MVVM.Shared\Windows\Windows\DataWindow\DataWindow.cs:line 892
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)