Chapter 7. Dialogs and MVVM
By Muhammad Shujaat Siddiqi
In WPF, dialogs are similar to those in Winform. The only way to show dialogs is by using either Window.Show()
(modeless) or Window.ShowDialog()
(modal) methods.
Note
This includes built-in dialogs, such as
MessageBox
,
OpenFileDialog
, SaveFileDialog
, and PrintDialog
.
Since we need our view model logic to be able to initiate the display of these dialogs, we might be tempted to call these methods directly from our view models. The problem with calling Show()
or ShowDialog()
directly is that it requires the System.Windows.Window
references to be held by view model coupling ViewModel
to System.Windows
. This breaks down the desired separation of concerns in MVVM and makes things like testing our code more difficult than it needs to be.
There is another issue around dialog ownership as you must set a dialog's owner to be the window that will be its parent. Even if we show our dialogs directly from our view models, we still will not be able...
Should we make a compromise?
The preceding discussion might lead you to think that we have no solution to display dialogs in an MVVM fashion or you might think that it's not worth the effort. As we will see there are definitely options and we've already looked at the benefits that will be provided by putting in that extra effort. The MVVM community has devised many different ways to deal with this problem and just like everything in development there are tradeoffs to each approach. In this chapter, we are going to discuss some of these approaches. We will be discussing how we can show both, modal and modeless dialogs with these technique. We will also discuss how these dialogs can return data, which can be used by the view model using these techniques. The options we are going to explore in this chapter are as follows:
Dialog service
Mediators
Attached behavior
Dialog service is an approach where a layer of abstraction is used to show dialog boxes. View models delegate the responsibility of showing the dialogs to a dialog service and simply provide the service the data needed for display. The dialog service owns the responsibility of showing dialogs and we are able to keep our view models decoupled from System.Windows
and avoid the need for references from our views to our view models. In unit tests, we can inject a fake dialog service instance instead of showing the actual dialog and use our fake object for stubbing and mocking.
Let's consider a simple example WPF MVVMLight
project to show a dialog box using dialog service. The following view has a TextBlock
and a Button
. Clicking on the button should display a dialog box.
The XAML definition of the view can be as follows:
Mediators are the implementation of Gang of Four's Mediator pattern. In MVVM-based applications, they can be used to connect different disconnected parts of the application. Mediators aren't available directly in WPF or Silverlight but most of the MVVM toolkits have provided a mediator implementation. PRISM and MVVM Light have the EventAggregator
and Messenger
respectively as mediators. They are implemented based on Publisher/Subscriber model. One party publishes a message and if any other part of the application has subscribed to that message then the mediator hands message over to them. If, however, there are no subscribers then the message is ignored. Mediators generally have no limitations on the number of subscriber for a particular message so it could also be used for broadcasting certain information like Disconnected from Server or Logging off. Messages are generally received by a subscriber on the same thread that it was published on. Some MVVM toolkits allow publishing...
Attached behaviors are generally used to cause some code to be executed on the view based on some property changes in the view model. They are phenomenal for this purpose. They are also used to tackle non-MVVM features of otherwise MVVM-based controls. For example, when using Window
in WPF how can a view model cause it's associated window to be close? The only way to close a window is to directly call the
Window.Close()
method on the instance. Since we don't want our view models to hold references to our views, our view models cannot call Close()
method directly. Window
also does not have any DependencyProperty
that could be bound to a view model property to allow for closing the window. One way to resolve this problem is using an attached behavior. Using this pattern, our view model sets a notification-based property and rest is taken care of by using the attached behavior approach shown next. For this technique, we need to use INotifyPropertyChanged
, Data Triggers
...
There are many different approaches for incorporating dialog boxes in MVVM-based applications. We discussed how to use dialog service, mediator, and attached behavior based approaches. The dialog service takes advantage of DataTemplates. For the technologies that don't have DataTemplates automatically, we looked at using convention or configuration to achieve the same results.