C# WPF:以编程方式关闭窗口而不触发窗口关闭()

C# WPF:以编程方式关闭窗口而不触发窗口关闭(),c#,wpf,C#,Wpf,我正在制作一个应用程序,用户可以根据自己的需要动态创建更多的窗口。应用程序始终有一个MainWindow实例,并且将有0个或多个AuxWindow实例 添加更多的AuxWindow实例效果很好。但我在以编程方式再次关闭它们时遇到了问题(即,如果用户希望减少辅助窗口的数量)。从AuxWindow VM调用AuxWindow.Close()也会触发Window_Closing()方法,该方法开始请求用户确认 那么,我如何区分关闭窗口的用户和执行此操作的应用程序呢?如果用户关闭窗口,我想请求确认,然后

我正在制作一个应用程序,用户可以根据自己的需要动态创建更多的窗口。应用程序始终有一个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;
    }
}

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

然后我将在我的视图中实现此接口:

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构造函数中实例化视图时,我将VM作为参数传递,然后在视图构造函数中将VM设置为视图DataContext。对还是错?一般来说,视图模型不应该关心它的视图——这是MVVM范例的核心原则。这个话题相当复杂。你可以阅读更多关于它的信息,例如,在这里做一些研究,或者只是问另一个关于它的问题。谢谢你提供的信息。
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);
    }
}