One design time strategy

Visual studio (and Blend) provide great tools to help you get an awesome design, and see how your screens / pages / controls are going to look.  Yet I work with several developers who never use the designer, at all, and go 100% XAML. On the other hand, I like to see what I’m doing without having to launch the app to test every little tweak.

The idea behind MVVM is that your View, View Model and Model are separate and don’t know (or even need to know) about each othero. However, as I create a view, I will use data binding to bind some content of the view to the properties of the view model, and if those properties are only populated at runtime, then it can be hard to tell how out view will look in the designer.

There are several ways of making your design time experience, but ultimately, most come down to generating design time data, or using a design time view model.  I prefer the latter so it’s that which I will focus on here.

Design Time View Model

Here’s the route I currently prefer, creating a design-time view model. The main advantages of this are easily customizable design time data and design time intellisense for bindings. The down side is the design data may get compiled in to your solution, and you may need to re-build to see changes in the designer.

While you can use your run-time view model with a default constructor to populate some design time data, this has many restrictions (if your run-time version would also use a parameterless constructor, it can be hard to decouple effects of setting one property on others for example – remember it’s real code being run). Therefore, I prefer to create an entirely separate class for the design-time version. However, I also propose using an Interface to help with having parity between the bindable properties of the real and design time view models.

The example below is for a view model for displaying some weather data.

	//for design data, you only need the property getters - things you will Bind to
public interface IWeatherDataViewModel
{
   string Location { get; }
	int CurrentTemp { get; }
	int TodaysHigh { get; }
	int UVlevel { get; }
	string TemperatureUnits { get; }
}

//real implementation has dependencies, etc
public class WeatherDataViewModel: ViewModelBase, IWeatherDataViewModel
{
    public WeatherDataViewModel(WeatherModel model, Settings settings)
    {
        this.model=model;
        this.userPrefernces = settings;
        RefreshModelCommand= new DelagateCommand(executeRefreshModel);
    ....
    }

    public string Location => userPrefernces.SelectedLocation.DisplayString;
    public int CurrentTemp => model.CurrentTemp;
    public int TodaysHigh => model.HighTemp;
    public int UVlevel => model.UV;

    public string TemperatureUnits => userPrefernces .SelectedUnits.DisplayString;

   
}

//Design time class just has raw values and parameterless constructor
public class WeatherDataDesignViewModel : IWeatherDataViewModel
{
	public string Location => "Minneapolis";
	public int CurrentTemp => 85;
	public int TodaysHigh => 87;
	public int UVlevel => 7;
	public string TemperatureUnits => "F";
}

In the above example, the implementation has a command, which I could have added to the interface, since we will likely bind to it, but as the button to refresh the data isn’t likely to impact the view of the screen at design time I didn’t. However, I might do if I was using the CanExecute delegate and some particular enabled/disabled styling on the button to make sure that when CanExecute is false, the button looks ok.

Getting it into the XAML

Having created the designtime view model, using it in your view is easy.

<UserControl
  x:Class="MyWeatherApp.CurrentWeatherControl"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  ...
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"	
  xmlns:local="clr-namespace:MyWeatherApp"
  ...
  mc:Ignorable="d">	
  <Grid  d:DataContext="{d:DesignInstance local:WeatherDataDesignerViewModel, IsDesignTimeCreatable=True}">
....
</UserControl

The d:DesignInstance attribute tells XAML that the data context will be of a given type. This provides design time intellisese when creating bindings and the properties in this class will show in the list of choices. The IsDesignTimeCreateable attribute tells the designer in Visual studio that it’s OK to create an instance of this class at design time, and that means that it wil create an instance and use those properties that you assign to it. In this way, you can see what your app might look like with real data in at design time.

Tip: If you exclude IsDesignTimeCreatable, you can’t use it for design time data, but you do still get design time intellisense, even for view models that don’t have a parameterless constructor.

Considerations for UWP and x:Bind

If you use DataContext and traditional binding in UWP, the above will work exactly as I have already described it. But what about compiled bindings and x:Bind?

It looks like the current recommendation may be to use traditional bindings via DataContext until you are happy with your design, than swap to x:Bind for improved performance.

See this response on the GitHub for a sample application: Microsoft PhotoSharing App Sample issues. Hopefully there will be a better solution in future.

Hopefully you liked this look at one way of working with data at deign time. Which way do you like to see design time data be generated? Do you never use the designer and purely type you XAML? Let me know in the comments below.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.