I put dialog code into the View's CodeBehind. I still route the command through the ViewModel, but the ViewModel calls the View's implementation and gets the result.
Suppose I have MainWindow View (xaml), and a MainWindow ViewModel and I want to save a file.
In the codebehind View (MainWindow.xaml.cs) I add the code to create the dialog and return the save filename:
public FileInfo OpenSaveFileDialog(string title, string filter)
{
var dialog = new SaveFileDialog
{
Filter = filter,
Title = title
};
var result = dialog.ShowDialog();
if (!result.Value) return null;
return new FileInfo(dialog.FileName);
}
In the ViewModel I have a DoSaveFile() method:
public void DoSaveFile()
{
var file = OpenSaveFileDialog("Save File", "Super files (*.super)|*.super |All files (*.*)|*.*");
if (file == null) return;
//Save logic...
}
public DelegateCommand SaveFile { get { return Get("SaveFile", new DelegateCommand(DoSaveFile, () => true)); } }
In the MainWindow.xaml I have a button bound to to the delegate command:
<Button Content="Save File" Command="{Binding SaveFile}"/>
Like MVP, this implementation is chatty, but it works really well for test and separation of concerns. To me, it makes sense to leave the mechanics of window opening to the View class, even thought it feels a bit like an active-view.