mostly c# and wpf

MVVM

If you’re anything like me, you’re always coming up with new ideas for applications. Since WPF is my favorite UI framework, I usually end up creating it in C# and WPF. Things go great for a while, the application gets to a working state and I’m ready to preview it to the world (or a friend), but there’s still one thing I need to do – the settings screen.

The requirements for a setting screen can vary depending on the complexity of your application, but even the simplest ones usually have a handful of settings. Every time I get to this stage of the process I end up slacking off and not really finishing it properly.

So, here’s my one-stop solution to never having to create another settings screen ever again. Just implement the steps below and you’ll have a simple settings screen that binds to a class with special attributes to handle some of the finer details. Let’s jump in –

Settings Classes

First we need a simple class to contain our settings. In this example we’ll just stick with 5 settings

Now, obviously, you’re probably storing these settings somewhere, either in SQL or some kind of file, but I’ll leave those details up to you.

We want to be able to add some data to these settings so we can display a description of the setting to the user on the Settings screen. There may be some other data you’ll need to add to them to organize the settings or even hide some from the user. To do this, we’re going to create an Attribute class –

ViewModels

Now we can create the ViewModel for the Settings View. The goal in the SettingsViewModel is to read all the properties from AppSettings using reflection and create a list of SettingsItemViewModels. Let’s start with the SettingsItemViewModel. I have it inheriting from MVVMBase which is a base class that inherits INotifyPropertyChanged. If you’re looking for an MVVM framework may I suggest JustMVVM, I wrote it, but it’s the simplest MVVM framework around, and that’s why I did it.

So, this class above is a generic class that can contain any type of setting. This way we can create a list of them, one for each of the properties in AppSettings. The real key to this is using the dynamic type for the property Value. It allows us to set it generically and then check if afterwards to find out the type. IsDirty can also be useful to tell if the setting was actually changed. We’ll see that below.

Here’s the code for the SettingsViewModel which is the view model for the SettingsView UI.

OK, we’ve now got our ObservableCollection<SettingsItemViewModel> ready to go for the View. Let’s take a look at what needs to happen there.

View

OK, the View is pretty straight forward. We’re going to use an ItemsControl to contain our list of settings and we’ll use DataTemplates to figure out what view to display for each setting. Hopefully this will become more clear after you look at the code –

The ContentControl inside the ItemsControl has a bunch of triggers that displays a different DataTemplate based on the SettingType of the SettingsItem. This allows us to have different views for each type. Obviously the view for a Boolean settings will be some kind of a checkbox, while the view for an enum would probably be a combobox.

Here are the data templates used to make this magic happen. If you don’t know too much about data templates, this is a good resources. These need to be placed in the resources section somewhere in the View. In this case I put it in the ItemsControl.Resources section.

Alright. Everything’s linked up now. Obviously you can add to this if you have more complicated settings. Some settings may even be complete other classes. Either way, this setup should work pretty smoothly for you.

Converters

Here’s a couple of extra pieces that make it easier to use enums with comboboxes for settings (I’m assuming you have some). They’re just a couple of simple converters that let you bind to an enum without having to explicitly mention the enum type.

That’s it. Let me know what you think in the comments. I’m always looking for feedback. I’ve been thinking of some variation of this setup for a while now, and I’m looking forward to never manually creating another settings screen ever again.

I spent some time today working on DataTemplateSelectors. I’d never used them before, but it made me think about all the different ways there are to set the DataContext in WPF. After talking through this with a friend, I realized that maybe some of these minor nuances aren’t very clear. I figured if I write about it, at least I can reference it again later when I forget.

OK, my first assumption here is that you’re being a good programmer and using MVVM, this is WPF after all.

Binding To Code-Behind

This is the most basic kind of binding. When you first learn MVVM, this is probably going to be your first step. Binding to code-behind just requires you to set your DataContext to the xaml.cs file attached to your View –

Make sure to get the correct namespace (in this case local) of your View Model. When using this style of datacontext setting, you’re going to have to do this for each and every View. At first this might seem OK, but the further into this you get, the more cumbersome this method becomes.

OK, onto the next method; DataTemplates!

Binding Using DataTemplates

DataTemplates are used all over WPF (seriously, you should take a look into how awesome data templating is in ListViews if you don’t believe me). When it comes to Views and View Models the data template allows you to load your Views by specifying the View Model you want. Instead of loading View first, you can call the View Model (along with it’s constructor) and the ContentPresenter will figure out what View to serve up alongside it.

The beauty of this is you can now pass around data between your view models, making it easier to structure your program.

You still need to set the DataContext of your initial entry point View. In the case above it’s the MainWindow and MainWindowViewModel. So, even in this method, make sure to set the DataContext first.

Now, add some kind of presenter (it can be a ContentPresenter, ContentControl or UserControl). This will be the View Controller that will change out the different views according to your bindings. Here’s the code for the View –

Here’s the code for your View Model (I’m not including the INotifyPropertyChanged interface, I’m assuming you’ve got that figured out by now, but if you’re looking for a framework, try JustMVVM). MVVMBase is just a base class that all View Models must inherit from.

For the application to figure out what view to load for the ContentPresenter, we need to add a Data Template. The simplest place to put this is in App.xaml, then it’ll work throughout the entire application, but in reality you can put this in any Resources section

For most of my applications that I’ve worked on, this has worked out great. I have a single spot where I put all my data templates and then I’m in complete control over what views are being loaded. There are occasional situations that require an even more complicated solution, so here we go, my final option, the DataTemplateSelector.

Data Template Selector

In theory this is another alternative to using Data Templates, but it gives a little more control over the issue. Sometimes a need arises where you have multiple Views for a single View Model, or you’ve created a generic form of ViewModel<T> but you can’t define a DataTemplate for generics in XAML. In this case, you can create a Data Template Selector, which allows you to select the associated View template in code.

Let’s unpack this a little bit. The properties at the top can be set in the XAML to the data templates we created in the previous section (see below for how it’s done). The first part of the if statement shows how you can handle a generic type for a template selector. This means that any HomeViewModel<T> will load the HomeTemplate.

The reason I ended up using this over Data Templates is for the else part at the end. I was creating a library that was to be consumed by others. I wanted to be very specific about what templates were loaded in my library, but also leave open the possibility of other people adding their own templates. I guess I could have created some extensible class that allows people to add more templates, but by calling the base implementation of the DataTemplateSelector

return base.SelectTemplate(item, container);

I don’t have to do anything special, I just let the normal DataTemplates take over again like usual.