WPF MVVM - 在Window Closing事件中显示MessageBox

时间:2017-11-01 02:19:12

标签: c# wpf mvvm catel

[我标记了Catel,但我认为这个问题适用于任何MVVM框架。]

本网站上有一些建议用于处理关闭事件(特别是来自“红色X”按钮),程序员希望检查应用程序是否可以关闭或显示“你确定吗?”对话框。我已经尝试了三个 - 完全在View中处理事件,使用事件触发器从XAML调用ViewModel上的命令,并让View将事件处理连接到ViewModel事件处理程序。当用户试图按预期关闭窗口时,将触发所有这三种方式。

我的问题是,如果我尝试在事件处理程序中显示MessageBox以获得User的确认,我会收到以下异常:

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.

正在关闭的窗口是我的主窗口,所以如果它关闭,我的应用程序也是如此。我知道我可以通过将CancelEventArgs.Cancel值设置为true来取消Window的结束。

我如何捕获Closing事件然后让我的处理程序根据User的输入确定是否实际关闭?

如果您需要更多信息,请告诉我们。谢谢!

编辑:这是我用来处理Exit Application菜单命令的内容:

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();
        }
    }
}

messageService和navigationService调用是Catel服务/方法。记录器是NLog。

这在作为命令处理程序运行时有效,因为在完成所有检查之前Window不会关闭。如果我尝试在Closing事件处理中注入相同的逻辑,我会得到上面提到的异常。

这是堆栈跟踪的一部分:

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)

4 个答案:

答案 0 :(得分:0)

基本上,如果我想管理应用程序/窗口的打开和关闭过程,我会尝试直接从Application进程控制它。这是一些非常粗略的代码:

public partial class App : Application
{
    public MainWindow window = new MainWindow();
    void App_Startup(object sender, StartupEventArgs e)
    {
        window.Show();
        window.Closing += manageClosing;
    }
    void manageClosing(Object sender, System.ComponentModel.CancelEventArgs e)
    {
        MessageBox.Show("It won't close");
        e.Cancel = true;
    }
}

答案 1 :(得分:0)

如果您正在使用Catel并使用DataWindow / Window类,则可以在MainViewModel::SaveAsync中简单地询问此问题。如果您返回false,窗口将不会关闭(Catel已经为您处理此事)。

答案 2 :(得分:0)

在显示Cancel之前,将CancelEventArgs的{​​{1}}属性设置为true。这对我来说很好用:

MessageBox

答案 3 :(得分:0)

在事件处理程序中,最好使用Dispatcher处理任何耗时的代码,包括对话框。这避免了事件处理程序的两次触发。参见Dispatcher BeginInvoke Syntax