Webinar: Using DevExpress MVVM Magic with WPF

25 August 2016

This week, I presented a webinar about our MVVM framework which ships with our WPF control suite. In case you missed it, you can watch it here.

image

What is MVVM and why?

MVVM stands for Model-View-ViewModel and it is a design pattern which requires you to make some architectural choices before you start on a project. I will only spend a little time on the ‘why’ since there are tons of great articles out there doing a way more detailed job.

image

The most important advantages in my opinion are:

Seperation of concerns

In this case, the View (U.I.) does not have any direct relation with the DataLayer (Models). The ViewModel provides all the presentation logic and accesses the DataLayer if needed.

In most applications, data is stored in a relational database. The structure of your database is in most cases optimized to select and/or update information as quickly as possible. Also in most cases, this is not the most optimal way for presentation purposes. The ViewModel gives us the possibility to transform the data coming out of the DataLayer into an optimized (different) structure for presentation purposes.

By using this approach, we can use one of the very powerful features of the WPF platform – databinding. The View databinds certain elements in the U.I. to properties or commands exposed by the ViewModel. As a result, in most cases there is no code-behind in a View.

UnitTestable

Another cool side effect of this pattern is that – because the ViewModel doesn’t care what is bound to it – we can replace the View with a UnitTest. Since all presentation logic is coded in the ViewModel, this means that we can UnitTest the presentation logic.

Why did we build such a framework?

While WPF is designed to support a lot of aspects of the MVVM design pattern, some things do require some coding in the ViewModels. To give you an example: A ViewModel is unable to interact directly with the UI, but what happens when some validation code in the ViewModel needs to raise a confirmation on the UI?

This is implemented through Services and Behaviors and is something available out of the box through our framework. There are a couple more difficulties in this loosely coupled architecture which are managed easily through the framework.

We also provide you with some really awesome design-time support built in to easily bind all kinds of things to the ViewModel. This support is provided with all DevExpress WPF controls.

This all results in less code in your ViewModels which keeps things nice and clean.

An introduction of the Framework

The MVVM framework is convention based. This means that there are certain guidelines you need to follow and by doing so, you’ll be able to build applications in less time.

In the webinar I created a ViewModel based on a number of those conventions. The bare minimum code for a ViewModel looks as follows:

[POCOViewModel]
public class TrackViewModel
{
    public virtual TrackInfo Track { get; set; }

    [ServiceProperty(SearchMode = ServiceSearchMode.PreferParents)]
    protected virtual IMessageBoxService MessageBoxService { get { return null; } }

    protected TrackViewModel()
    {
        // for test purposes only !!
        Track = new TrackList()[15];
    }
    public static TrackViewModel Create()
    {
        return ViewModelSource.Create(() = > new TrackViewModel());
    }

    public bool CanResetName()
    {
        return Track != null & amp; & !String.IsNullOrEmpty(Track.Name);
    }
    public void ResetName()
    {
        if (Track != null)
        {
            Track.Name = "";
        }
    }
}

In the code there are a couple of interesting points.

  • The class is decorated with the [POCOViewModel]
  • Properties (for binding purposes) are marked virtual
  • The constructor is marked protected which means that we cannot instantiate such a ViewModel directly
  • There is a public static Create method which instantiates a new instance of this ViewModel through the ViewModelSource factory
  • The method bool CanResetName has a relation with method ResetName

The creation of an instance of this class through that factory is essential for the magic to happen. What happens under the hood is that the framework creates a new ViewModel class which is derived from our ViewModel. In this derived class, we add all kinds framework related things to the ViewModel. For instance, we create Commands for public methods, we set constraints depending on the results of those bool Can… methods.

Also the IMessageBoxService MessageBoxService property - which just returns null - will have changed behavior in the derived class.

Once we have set everything up according to those conventions (and did a build), we’re able to switch to the View. Through the Task Menu of any of the controls, we’ll be able to use those design-time features which come with the framework.

image

During the webinar I introduced a second View + ViewModel and I demonstrate how one ViewModel activates another and synchronize some data. I also show how easy it is to map events (from the grid) to commands in the ViewModel by binding expressions.

UnitTesting

If you want to perform a test on one of the ViewModels, you can setup a test like:

[TestFixture]
class TrackViewModelTests
{
    const string INITIAL_TRACKNAME = "My Test Track";
    const string MODIFIED_TRACKNAME = "My Modified Test Track";

    [SetUp]
    protected void SetUp()
    {
        // initialize your test here
    }

    [Test]
    public void TestResetNameCommandNo()
    {

        var vm = TrackViewModel.Create(new TrackInfo() { Name = INITIAL_TRACKNAME });
        var serviceContainer = (vm as ISupportServices).ServiceContainer;

        IMessageBoxService msgSvc = new DummyServiceForMessageBox(MessageResult.No);
        serviceContainer.RegisterService(msgSvc);

        //Testing the ResetName behaviour while clicking No on the confirmation dialog...
        vm.ResetName();
        Assert.That(vm.Name, Is.EqualTo(INITIAL_TRACKNAME));
    }
}

Do note that the DummyServiceForMessageBox can be a simple class which looks like:

internal class DummyServiceForMessageBox : IMessageBoxService
{
    private readonly MessageResult resultToTest;
    public DummyServiceForMessageBox(MessageResult resultToTest)
    {
        this.resultToTest = resultToTest;
    }
    MessageResult IMessageBoxService.Show(string messageBoxText, string caption,
        MessageButton button, MessageIcon icon, MessageResult defaultResult)
    {
        return this.resultToTest;
    }
}

Because these services are interfaced based, we can simple change the implementation of this DummyServiceForMessageBox from showing the dialog to an immediate Yes or No.

The Demo Project

The project I have created during the webinar is available on github at: https://github.com/donwibier/DXWPF-MVVM-Magic.git

I have also included an NUnit test project to demonstrate how to test one of those ViewModels.

Let me know what you think of the framework and if you are ready for a deep-dive webinar!

1 comment(s)
Matthieu Gobillot

Hi Don,

I attended the webinar and despite I already walked through the DevExpress MVVM framework on my own using the Online Documentation, I was glad to have additional informations and details from someone who handles it well.

It is always good to know about writing conventions so you can let them aside once you understand what they do (eg : the static Create method and the protected constructor).

Thanks for sharing the source code, especially the NUnit part because many people talk about it but only a few do cover the subject concretely.

I have been developing in C# for many years and have switched to WPF with a MVVM approach for 8 months now.

I was commissioned to find MVVM compliant WPF components for my company. Here are some of my thoughts :

* DevExpress is the only editor which provides such a MVVM framework. Moreover it is shared for free.

* That framework not only respects the MVVM pattern but also brings a direct benefit to the developer by reducing the amount of code to implement WPF functionalities (Notification, Command, ...) => That is really a huge plus !

* Unconventional Properties may be trickier to manage in POCO ViewModel, though it is possible. Maybe I need some training ;)

* The Services and Behaviors are really great once you manage to know how and when to use them.

* Theme management is also great. Theme customization seems more complicated as I am not a designer.

* Localization lacks the French language. I know about the Online Service, but I would have prefered an out of the box solution.

It would be a pleasure to attend other webinars like :

* deeper in the MVVM framework.

* detailed presentation of Data Editors to create custom ones more easely. The documentation is quite good but one has got to catch the spirit behind the Data Editor concept to unleash its benefits.

* a full NUnit cover.

* even deeper in the MVVM framework !

Thanks,

Matthieu

2 September, 2016

Please login or register to post comments.