【问题标题】:WPF: Closing a window programmatically without triggering Window_Closing()WPF:以编程方式关闭窗口而不触发 Window_Closing()
【发布时间】:2017-09-13 15:43:41
【问题描述】:

我正在制作一个应用程序,用户可以在其中根据需要动态创建更多窗口。应用程序始终有 一个 MainWindow 实例,并且将有 0 个或多个 AuxWindow 实例。

添加更多 AuxWindow 实例可以正常工作。但是我在以编程方式再次关闭它们时遇到问题(即,如果用户想要减少辅助窗口的数量)。从 AuxWindow VM 调用 AuxWindow.Close() 也会触发 Window_Closing() 方法,该方法开始要求用户确认。

那么我如何区分用户关闭窗口和应用程序关闭窗口呢?如果用户关闭窗口,我想要求确认,然后关闭整个应用程序。但如果应用程序正在关闭窗口,我只想关闭它。

这是 AuxWindow 中的 Window_Closing() 方法:

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
    _logger.Info("Exit application initiated - closing window");
    var result = _auxWindowVM.Controller.ExitApplication(this);
    if (result == false) {
        _logger.Info("Closing application confirmed");
        e.Cancel = false;
    }
    else {
        _logger.Info("Closing application canceled");
        e.Cancel = true;
    }
}

这是从 MainWindow 和所有 AuxWindow 实例调用的 ExitApplication 方法:

public bool ExitApplication(Window initWindow) {
    if (_exitConfirmed == false) {
        if (System.Windows.MessageBox.Show("Are you sure you want to exit?", "", System.Windows.MessageBoxButton.YesNo, System.Windows.MessageBoxImage.Question, System.Windows.MessageBoxResult.No) == System.Windows.MessageBoxResult.Yes) {
            MainWindowVM.CurrentDateTimeUpdateTimer.Stop();
            SerialPortHandler.SerialPortCts.Cancel();
            ArgusMk2CommProtocol.QueueConsumerCts.Cancel();
            PollingHandler.PollingTimer.Stop();
            _exitConfirmed = true;
            Application.Current.Shutdown();
            return false;
        }
        else {
            return true;
        }
    }
    else {
        return false;
    }
}

【问题讨论】:

    标签: c# wpf


    【解决方案1】:

    我会为AuxWindows 引入一个接口来处理这个问题。 (为什么是接口?只是为了确保视图和视图模型之间没有紧密耦合,请参阅 MVVM 和 SOLID。)

    interface ICloseableView
    {
        void Close(bool confirmClose);
    }
    

    然后我会在我的视图中实现这个接口:

    class AuxWindow : Window, ICloseableView
    {
        private bool confirmClose = true;
    
        public void Close(bool confirmClose)
        {
            try
            {
                this.confirmClose = confirmClose;
                Close();
            }
            finally
            {
                this.confirmClose = true;
            } 
        }
    
        private void Window_Closing(object sender, CancelEventArgs e)
        {
            if (!this.confirmClose)
            {
                e.Cancel = false;
                return;
            }
    
            // Your code here...
        }
    
    }
    

    最后,在AuxWindow的视图模型中,我会使用这个方法通过接口引用获取它。请记住:视图模型不应该知道具体的视图实现,因此为视图模型提供AuxWindow 引用是一种不好的做法,但给它一个IClosableView 引用是完全可以的:

    class AuxWindowViewModel : INotifyPropertyChanged
    {
        private readonly IClosableView view;
    
        // E.g. use a dependency injection via constructor
        public AuxWindowViewModel(IClosableView view)
        {
            this.view = view;
        }
    
        void CloseViewWithoutConfirmation()
        {
            this.view.Close(false);
        }
    }
    

    使用这种方法,用户在通过 GUI 或键盘快捷键以“正常”方式关闭 AuxWindow 时总是会得到一个确认对话框。但是从视图模型中关闭视图不会显示该对话框。

    【讨论】:

    • 关于本地布尔值检查操作员是否需要确认的好主意。但是如何在没有引用的情况下从 VM 实例化视图(我被教导是“正确”的方法(这是错误的吗?))?目前,我在 VM 构造函数中实例化 View 时将 VM 作为参数传递,然后在 View 构造函数中将 VM 设置为 View DataContext。对还是错?
    • 一般来说,视图模型不应该关心它的视图——这是 MVVM 范式的核心原则。题目相当复杂。您可以阅读更多关于它的信息,例如here,在这里做一些关于 SO 的研究,或者只是问另一个问题。
    • 感谢您的信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-17
    • 2017-11-24
    • 1970-01-01
    • 1970-01-01
    • 2011-08-01
    • 1970-01-01
    相关资源
    最近更新 更多