tags:

views:

92

answers:

2

I'm just getting up to speed on MVVM, but all the examples I've seen so far are binding View controls to simple non-WPF specific data types such as strings and ints. However in our app I want to be able to set a button's border brush based on a number in the Model.

At the moment, I translate the number into a brush in the ViewModel to keep the View XAML only, but is that right?

I don't like putting WPF specific code in the ViewModel, but equally I don't like the idea of putting code-behind on my View panel.

Which is the best way?

Thanks

+2  A: 

Try custom ValueConverter.

What's the purpose of keeping your view XAML only? Keeping ViewModel clean makes sense because of testability and SoC. But no codebehind?

majocha
I read somewhere that it's a good idea to minimize code-behind on a view, in order to minimise platform specific code (and also to help with unit testing). But then the issue was how to avoid this WPF specific (in my case) code polluting the VM instead, hence the question. Well done for suggesting ValueConverter first, for which I've marked up your answer, but Reed's answer was more detailed, so I gave him the tick. Thanks!
Surfbutler
As your app grows it's usually not possible to keep codebehind empty. Isues like handling focus and customizing some controls behavior are more related to the design, not the model, so codebehind is natural place for them.
majocha
Ok that's interesting, I was thinking I could never put any code-behind in my View when using MVVM, but it's reassuring to know that, you at least, think it's not neccessary, or even possible. Thanks again.
Surfbutler
+6  A: 

At the moment, I translate the number into a brush in the ViewModel to keep the View XAML only, but is that right?

No, not really.

Ideally, you should keep WPF dependencies out of your ViewModel. This helps allow your application to be more testable, but also easily translatable to Silverlight or other technologies in the future.

WPF provides a mechanism for this exact scenario, however: IValueConverter. It is very easy to make a ValueConverter that does the translation from an integer, string, or any other type, into a brush. The Data Binding Overview shows an example of translating from a Color to a Brush using a Value Converter.

This is a much better design in the long run... "Brushes" and other WPF concepts are really part of the View - they aren't tied to your logic. Your ViewModel should think in terms of state, and your View should translate that state to a specific way to represent the state.

Say you want to use a "red" brush to display an error. Instead of the ViewModel exposing a brush, it should expose some primitive (ie: a bool property) such as IsInErrorState. The View should decide how to represent this - whether it be via a red brush, a big warning, etc... Converters allow this to happen in a purely XAML manner.


In your case, the ValueConverter is easy. Since you're going from a Number -> Brush (though I'd recommend using a custom Enum instead of an int), you can just do something like:

[ValueConversion(typeof(int), typeof(SolidColorBrush))]
public class IntToBrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        int option = (int)value;
        switch(option)
        {
            default:
                return Brushes.Black;
            case 1: 
                return Brushes.Red;
            case 2: 
                return Brushes.Green;
           // ...
        }

    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        // No need to convert back in this case
        throw new NotImplementedException();
    }
}
Reed Copsey
Thinking about this more, I agree with you. Certainly something like a Brush shouldn't be exposed, because a designer may have different ideas about how a particular state should be visualized. This is the more fundamental issue: exposing WPF-specific code usually means you'd be exposing some detail of visualization, rather than a detail of the state that should be visualized. A VM is tightly coupled to its View, but the responsibilities should still be clearly separated.
Dan Bryant
Thanks Reed, just what I was looking for.
Surfbutler