Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Window.Closing event handler in MVVM

Tags:

c#

mvvm

wpf

Following question is based on comment in this post: MVVM Understanding Issues

I said that this is codebehind, that does not violate the view and viewmodel separation of concerns:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Closing += MainWindow_Closing;
    }

    void MainWindow_Closing(object sender, CancelEventArgs e)
    {
        var canExit = ViewModel.ShowConfirmExitDlg();
        if (!canExit) e.Cancel = true;
    }
}

The comments was:

Anything in code-behind can't be unit tested, and invoking the creation of a dialog box is logic and therefore shouldn't be in the view

I have two questions:

  1. Does this break MVVM separation of conerns?
  2. How would you do it (better)?

I could call the viewmodel method from xaml using some EventTriggers and CallMethod actions, but it does not make any difference.

I could do use event aggregator:

public partial class MainWindow : Window
{
    private readonly IEventAggregator _eventAggregator;

    public MainWindow(IEventAggregator eventAggregator)
    {
        _eventAggregator = eventAggregator;
        InitializeComponent();

        Closing += MainWindow_Closing;
    }

    void MainWindow_Closing(object sender, CancelEventArgs e)
    {
        var evt = new MainWindowClosingEvent();
        _eventAggregator.Publish(evt);
        e.Cancel = evt.IsCancel;
    }
}

and handle the event in viewmodel but does it bring any value? I still cannot unit test cancelling the windows closing event, but I have introduces publishing and subscribing that would be also worth unittestig. It's yet another layer of indirection

Maybe I could route the event to viewmodel:

public MainWindow()
{
   InitializeComponent();
   Closing += ViewModel.OnWindowClosing;
   //or
   Closing += (o, e) => ViewModel.OnWindowClosing(e);
}

but I don't see much difference with the original sample.

IMHO, the connection between view and viewmodel cannot be unittested in viewmodel tests, so I either find a way how to test views or it is wild goose chase.

like image 287
Liero Avatar asked Mar 15 '23 23:03

Liero


1 Answers

There are two issues here, as I see it. Firstly, you can eliminate some of that code-behind by using the interactivity namespace and commands, for reference look into:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

<i:Interaction.Triggers>
  <i:EventTrigger EventName="Closing">
       ICommand goes here - bind to your VM
  </i:EventTrigger>
</i:Interaction.Triggers>

when it comes to showing dialogs, you need to consider whether the dialog is view or view-model. When it comes to confirming the window closure, I think of that as purely view. So you can show that inside the code-behind of the Closing event, without IMHO breaking MVVM.

like image 121
user3690202 Avatar answered Mar 28 '23 19:03

user3690202