Reputation: 1322
I'm making an application where the user can dynamically create more windows according to their needs. The application always has one instance of MainWindow, and will have 0 or more instances of AuxWindow.
Adding more AuxWindow instances works fine. But I'm having problems closing them again programmatically (i.e. if the user wants to reduce the number of auxilliary windows). Calling AuxWindow.Close() from the AuxWindow VM also triggers the Window_Closing() method, which starts asking the user for confirmation.
So how do I differentiate between the user closing the window and the application doing it? If the user closes the window, I want to ask for confirmation and then close down the whole application. But if the application is closing the window, I just want it closed.
Here's the Window_Closing() method in AuxWindow:
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;
}
}
And here's the ExitApplication method being called from both MainWindow and all AuxWindow instances:
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;
}
}
Upvotes: 1
Views: 1652
Reputation: 15227
I would introduce an interface for the AuxWindow
s for handling this. (Why an interface? Just to ensure there's no tight coupling between the views and the view models, see MVVM and SOLID.)
interface ICloseableView
{
void Close(bool confirmClose);
}
Then I would implement this interface in my views:
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...
}
}
Finally, in the view models of the AuxWindow
, I would use this method obtaining it via the interface reference. Remember: a view model should not be aware of the concrete view implementation, so it's a bad practice to provide a view model with a AuxWindow
reference, but it's perfectly OK to give it an IClosableView
reference:
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);
}
}
Using this approach, the user will always get a confirmation dialog whenever they close the AuxWindow
in a "normal" way via the GUI or a keyboard shortcut. But closing the view from the view model won't show that dialog.
Upvotes: 2