Modal Dialogues & MVVM
Lots of discussions around this particular subject. More generally the topic should be opening Modal Dialogues under MVVM. Who’s responsibility should it be?
- View
- ViewModel
- Other Actor
As always there are pros and cons against all of the above.
View
The MVVM brigade would say that the View should never initiate opening a dialogue, modal or otherwise. I do not share that view, (no pun intended). Where the dialoue is an aid to UI, then I believe it is the responsibility of the View to control the dialogue. Classic example would be a File/Directory selection dialogue. These dialogues are there as UI friendly routes to populate UI controls, and in that respect fall into the same class as Drop-Down selection controls . It is purely a UI activity. It does not, of itself, interact with the Model, and the control over its presentation is most definitely not the responsibility of the ViewModel.
If you let the View open the dialogue, then you will be generating Code-Behind, and some would take that as blasphomous. Again I do not agree, the main reason for avoiding Code-Behind in the view is because of the difficulty (near impossibility) of unit testing. But we do not unit test UI controls. We do not unit test Check-boxes, Radio Buttons, Drop Downs, Text Boxes….. so I see nothing wrong in not having a unit test for displaying a File/Directory Selection control. From my perspective, including code-behind to manage a UI assistant dialogues is fine.
My approach to FileSelection is to construct User Control comprising:
- Label
- TextBox
- Button
<UserControl mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Margin="0,2,0,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label x:Name="FileDialogLbl" Grid.Column="0" MinWidth="150"/>
<Button x:Name="FileDialogBtn" Grid.Column="2"
Click="FileDialogBtn_OnClick" >
Browse...
</Button>
<TextBox x:Name="FileDialogTbx" Grid.Column="1" Margin="2,0,2,0"
MinWidth="200" VerticalContentAlignment="center">
</TextBox>
</Grid>
</UserControl>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using Microsoft.Win32;
namespace C_V_App.UserControls
{
/// <summary>
/// Interaction logic for FileSelectionControl.xaml
/// </summary>
///
[ContentProperty ("Label")]
public partial class FileSelectionControl : UserControl
{
public static readonly DependencyProperty FileNameProperty = DependencyProperty.Register("FileName", typeof(string), typeof(FileSelectionControl));
public FileSelectionControl()
{
FileDialogue = new OpenFileDialog();
InitializeComponent();
}
private OpenFileDialog FileDialogue { get; set; }
public void FileDialogBtn_OnClick (object sender, RoutedEventArgs args)
{
FileDialogue.ShowDialog();
this.FileDialogTbx.Text = FileDialogue.FileName;
}
public string Label
{
get { return this.TitleLbl.Content.ToString(); }
set { this.TitleLbl.Content = value; }
}
}
}
ViewModel
As you can gather from the above discussion, I do not believe that modal dialogues that are purely UI centric should be managed by the ViewModel. And if you are doing that in order to avoid code-behind in the View, then I would say don’t. To me you are injecting a great deal of unnecessary code, and unnecessary complexitiy which does nothing to improve quality or understanding. Quite the opposite, you now have additional code that you cannot unit test, because opening the Dialogue cannot be Unit Tested. Yes you can Unit Test the underlying structured code, but you still cannot unit test the Dialogue passing its results back to the UI.
However, that does not mean I believe the ViewModel should never open Modal Dialogues. Quite the opposite. The majority of times it will be ViewModel that should trigger the dialogues. Message boxes are a prefect example. Others would be when a certain UI action requires the input of additional information. These are examples when a dialogue being displayed is occassioned by a change in state. In these circumstances it is absolutely the ViewModel that should control the display of the dialogue.
Other Actor
If you are really determined to remove all code behind, then the best structure I have seen for doing that and for completely eliminating any inter-dependency between the View and the Model Dialogue is to implement a Service where the Service implements an IService interface that