Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using WPF design data with the MVVM pattern

I'm using the MVVM pattern in our WPF application to allow for comprehensive unit testing. The MVVM pattern itself is working great, however I'm struggling to adapt the pattern in a way that means I can use the design-time data support of WPF.

As I'm using Prism the ViewModel instances are generally injected into the constructor of the view, like so

public MyView(MyViewModel viewModel)
{
    DataContext = viewModel;
}

Dependencies for the ViewModel are then injected into the constructor, like so

public class MyViewModel
{
    public MyViewModel(IFoo foo, IBar bar)
    {
        // ...
    }

    // Gets and sets the model represented in the view
    public MyModel { get; set; }

    // Read-only properties that the view data binds to
    public ICollectionView Rows { get; }
    public string Title { get; }

    // Read-write properties are databound to the UI and are used to control logic
    public string Filter { get; set; }
}

This is generally working really well except when it comes to design data - I wanted to avoid compiling design-data specific classes into my released assembly and so I opted to use the {d:DesignData} approach instead of the {d:DesignInstance} approach, however in order for this to work correctly my ViewModel now needs to have a parameterless constructor. In addition, I also often need to change additional properties either to have setters or to be modifiable collections in order to be able to set these properties in XAML.

public class MyViewModel
{
    public MyViewModel()
    {
    }

    public MyViewModel(IFoo foo, IBar bar)
    {
        // ...
    }

    // Gets and sets the model represented in the view
    public MyModel { get; set; }

    // My read-only properties are no longer read-only
    public ObservableCollection<Something> Rows { get; }
    public string Title { get; set; }

    public string Filter { get; set; }
}

This is worrying me:

  • I have a parameterless constructor that is never intended to be called and isn't unit tested
  • There are setters for properties that only the ViewModel itself should be calling
  • My ViewModel is now a jumbled mixture of properties that should be modified by the view, and those that shouldn't - this makes it tricky to tell at a glance which piece of code is responsible for maintaining any given property
  • Setting certain properties at design time (e.g. to see styling on the Filter text) can actually end up invoking ViewModel logic! (so my ViewModel also needs to be tollerant of otherwise mandatory dependencies being missing at design time)

Is there a better way to get design-time data in a WPF MVVM application in a way that doesn't compromise my ViewModel in this way?

Alternatively should I be building my ViewModel differently so that it has more simple properties with the logic separated out somewhere else.

like image 495
Justin Avatar asked Feb 08 '13 17:02

Justin


People also ask

Do you have to use MVVM with WPF?

The Windows Presentation Framework (WPF) takes full advantage of the Model-View-ViewModel (MVVM) pattern. Though it is possible to create WPF applications without using the MVVM pattern, a little investment in learning can make building WPF applications much simpler.

What is MVVM Architecture in WPF?

MVVM pattern has three separate layers of abstraction. Model: Model is mostly the database entities that represent the row data for the application. For Windows, application model is the entity class, which contains properties. View: For WPF applications view is the XAML based user interface.

Is WPF MVVM or MVC?

MVVM is written for desktop application with data binding capabilities – XAML and the INotifyPropertyChanged interface. If you want to do modification in the View-Model, the View-Model uses an observer pattern. The MVVM pattern is mostly used by WPF, Silverlight, nRoute, etc.

What is the MVVM design pattern?

Model-View-ViewModel (MVVM) is a software design pattern that is structured to separate program logic and user interface controls. MVVM is also known as model-view-binder and was created by Microsoft architects Ken Cooper and John Gossman.


1 Answers

First, I would recommend you to have a look at this video where Brian Lagunas provides several best practices about MVVM. Brian is - at least - involved in the development of Prism, as his name appears in the nuget packages information. Didn't check further.

On my side I only use bits of Prism, and my Model and ViewModel always offer blank constructors (like what Brian shows), the data context is assigned in the view's XAML, and I set the properties values like :

<MyView.DataContext>
  <MyViewModel />
</MyView.DataContext>

and

public void BringSomethingNew()
{      
  var myView = new View();
  (myView.DataContext as ViewModel).Model = myModel;

  UseMyView();
}

Another benefit with this approach is that the ViewModel is created once, with the same path at design and run time, so you create less objects and save GC efforts. I find this elegant.

With regards to the setters, the design data will still work if you make them private, like:

public string MyProp { get; private set; }

Ok, customize it to manage NotifyPropertyChange at your convenience, but you've got the idea.

Now, I don't have yet a solution to manage ObesrvableCollections (I face the same problem, although putting multiple values in XAML sometimes work... ???), and yes, I agree that you have to manage the case when the properties are not set, like setting default values in the constructor.

I hope this helps.

like image 55
Cédric Bourgeois Avatar answered Oct 13 '22 01:10

Cédric Bourgeois