Chapter 10. Using Non-MVVM Third-party Controls
By Muhammad Shujaat Siddiqi
The development community has been slow in adopting MVVM and as a result there are many third-party libraries and controls on the market that don't follow the pattern. One of the most common challenges faced when adopting MVVM is how to use non-MVVM libraries and controls in MVVM architecture. The good news is that we will review several techniques which will allow you to minimize the impact of the non-MVVM code in your design and maximize the testability of your codebase.
As an example, we are going to use the WPF WebBrowser control. This is complex enough example to explain all the different available techniques and yet simple enough to be covered in a single chapter. The WebBrowser
control is just a WPF wrapper around same old WebBrowser
ActiveX control from the Win32/MFC days. Like many Silverlight and WPF controls on the market, the WebBroswer
control wasn't built using the MVVM approach and instead has forms...
We can resolve the Binding
issue of controls exposing non-dependency properties by using attached behaviors. This technique is a simple matter of registering an attached property, which is implemented as dependency properties in WPF. We can use the attached property as a binding target and whenever the source value changes, we can pass the updated value to the non-bindable property.
To do this, add a new class called WebBrowserAttachedBehavior
and define it as follows:
Although attached behaviors seem to solve the limitation of binding to a binding target that isn't a dependency property, the approach can be less appealing if there are a large number of properties that we need to bind to. If we are using attached behaviors then we need to define an attached behavior for each property for each type of control we are using in our application. This can end up being a lot of work if we are using a lot of third-party controls and it would be nice if there was a simpler approach that required less coding and hence less maintenance. Fortunately, the binding reflector technique can come to our rescue.
We know the requirement that a binding target has to be
DependencyProperty
but the requirements for binding source are not so strict. A binding source can simply be a Plain Old CLR property. In the binding reflector technique, we capitalize on this flexibility. Using this approach, binding reflector is FrameworkElement
that is not available...
readonly CLR properties (with no change notification support)
The
WebBrowser
control also has readonly
CLR properties like CanGoBack
. When we get the value of this property, the control looks at its navigation list and determines if there are any pages in the list and returns true
if there are some navigable pages or false
otherwise. Like any other web browser, our web browser needs to support backward navigation, if possible. For this purpose, we want to include a
Back button on the interface. It seems like this would be easy to implement using the
CanGoBack
property. We could use this property in CanExecute
of ICommand
and use an instance of the command for this button. The only issue is that CanGoBack
is readonly
and does not support change notifications.
Using this approach, we will create an MVVM adapter around the non-MVVM control.
Note
The adapter pattern is a Gang of Four [GOF] pattern that involves adding a layer of abstraction over a class to change its interface. There are two approaches that can be taken when implementing the adapter pattern—inheritance based or aggregation based. In the inheritance version, you simply create a subclass of the class that needs to be adapted and then expose a new interface while the aggregation version involves aggregating the class and then making pass through calls from the adapter to the adaptee as needed.
We have to make a decision about whether we should implement an aggregation adapter or an inheritance adapter. Here, we can implement an aggregation-based adapter. This obviously needs more work than their inheritance counterparts for pass-through calls to the aggregated object. However, it's common to find that third-party libraries' types are sealed
for inheritance (like WebBrowser...
In this chapter, we discussed how we can use non-MVVM based controls in a MVVM based application. We discussed various techniques including attached properties, binding reflector, .NET 4.0 Dynamic, and MVVM adapters.