Skinning in WPF

I like writing XAML.  It gives me a sense of completion when I write a style of template by hand and it just works, I like using blend as well but raw is more fun Smile.

Lets say we have a requirement to change the front-end of a product for different brandings and “products” (that is, the same product with a different ‘skin’).  One of the challenges we have is that we don’t want to write new user controls every time the client screen needs to change (especially for something simple such as switching to a different style for certain builds).  What follows is a way of using the power of WPF resources to skin an application with little work.

we start off with 2 ListBoxes on a window, for the purposes of this article the list boxes are simple with a list of colours, as follows (they are both the same).

<ListBox Grid.Column="0" Margin="5"> 
    <ListBoxItem>Red</ListBoxItem> 
    <ListBoxItem>Yellow</ListBoxItem> 
    <ListBoxItem>Pink</ListBoxItem> 
    <ListBoxItem>Green</ListBoxItem> 
    <ListBoxItem>Orange</ListBoxItem> 
    <ListBoxItem>Purple</ListBoxItem> 
    <ListBoxItem>Blue</ListBoxItem> 
</ListBox> 

Now, this will just display 2 boring list so lets add a nice style in the app.xaml file for the left hand list as follows:

<Style x:Key="RoundedList" TargetType="{x:Type ListBoxItem}">
    <Setter Property="Width" Value="150" />
    <Setter Property="Margin" Value="5,2" />
    <Setter Property="Padding" Value="2" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <Border x:Name="border" BorderThickness="1" BorderBrush="Silver" Background="AliceBlue" CornerRadius="5">
                    <ContentPresenter x:Name="Content" Margin="0" HorizontalAlignment="Center" TextBlock.Foreground="Black" VerticalAlignment="Stretch" />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="Selector.IsSelected" Value="True">
                        <Setter TargetName="border" Property="Background" Value="Silver" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Adding the ItemContainerStyle ({StaticResource RoundedList}) to the list box will now give us something like the following:

image

As we can see we now have a nice styled list on the left which will change colour when we click on each item.  To demonstrate the skinning I am going to apply the same style to the right hand list but with a different name (so we now have 2 styles in the app.xaml file – RoundedList and RoundedList_skin).

So, for certain builds of this app we want the list buttons to shrink slightly when we click them but we only want it to do that for certain configurations.  We can add a new WPF resource dictionary to our project (Skin.xaml) and add the new style to it – it is important that the new style retains the name of the one it is replacing as we shall see shortly.

<Style x:Key="RoundedList_skin" TargetType="{x:Type ListBoxItem}">
    <Setter Property="Width" Value="150" />
    <Setter Property="Margin" Value="5,2" />
    <Setter Property="Padding" Value="2" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <Border x:Name="border" BorderThickness="1" BorderBrush="Silver" Background="AliceBlue" CornerRadius="5">
                    <ContentPresenter x:Name="Content" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Stretch" />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="Selector.IsSelected" Value="True">
                        <Setter Property="RenderTransform">
                            <Setter.Value>
                                <ScaleTransform ScaleX="0.85" ScaleY="0.85"/>
                            </Setter.Value>
                        </Setter> 
                        <Setter Property="RenderTransformOrigin" Value="0.5, 0.5"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
       </Setter.Value>
    </Setter>
</Style>

The transform in this style simply makes the item look as though it had been pressed.

And now for the actual trick of making the new skin available to the app thus replacing the defaults in App.xaml.  I need a new Application configuration file (App.config) with an appSetting (skins) to hold the required skins for this application build.  This is a comma-separated list of resource dictionaries that we are going to include in this build.  In order to allow the new skins to override the existing ones we are required to move the current resources that we have defined into a dictionary of their own (this is due to the scoping rules of merged dictionaries in WPF – the primary dictionary will always take precedence).  I am simply going to move them into a new dictionary called OriginalSkin.xaml and include this in my skins appSetting which now looks like this.

<add key="skins" value="OriginalSkin.xaml,Skin.xaml"/>

We now have the two dictionaries ready to be loaded.  In App.xaml.cs we need a new method to load the skins from the config and this should be called from the OnStartup method of the app (its virtual so is available right there in app.xaml.cs to be overridden).

private void LoadSkins()
{
    string skins = ConfigurationManager.AppSettings["skins"];
    if (string.IsNullOrEmpty(skins))
    {
        return;
    }

    string[] resources = skins.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
    foreach (string resource in resources)
    {
        ResourceDictionary dictionary = new ResourceDictionary();
        dictionary.Source = new Uri(resource, UriKind.Relative);
        this.Resources.MergedDictionaries.Add(dictionary);
    }
}

This code loops through the skins in the appSetting and adds them as merged dictionaries.  The beauty of this is that merged dictionaries are read in the order that they are added so the latter dictionaries will override the earlier ones resulting in our newly minted RoundedList_skin being called instead of the original one but the original version of RoundedList is still available for the other ListBox:

image

We can now add any number of skins to this configuration but we will only load the ones listed in the App.config file – this now makes the app very extensible and can be changed at the drop of a hat.

The sample application that I used for this post can be found here

MVVM – The ‘Other’ ViewModel

Something that we regularly do at work is add additional properties to business objects that are only for use on the client (isDirty, HasChanged …etc).  We have always just added these to the business object directly and thought nothing of it, but after listening to a Hanselminutes interview with Laurent Bugnion I discovered the ‘other’ use for a ViewModel – wrapping client side business objects to expose new properties.  This is also useful in removing the overhead of viewing objects via a converter.

I have recently started looking at ASP.NET MVC as well and the way to pass things between controller and view is by using a ViewModel class.  This overload of the term had not translated into being useable in MVVM as well so what follows is a short, simple example of using a ViewModel to better model some data to fit a view.

Lets say we have a meeting object that we have extracted from a service and it is now ready to display on our client.  This business object has no real relation to them ORM version of the same object if we are correctly differentiating between them and client facing business objects so it has no in-built tracking to determine if it has changed and we don’t want to send it back to the service for updating if nothing has changed.  Our class looks like this.

public class Meeting
{
    public Meeting()
    {

    }
    public string Subject { get; set; }
    public string Location { get; set; }
    public DateTime StartTime { get; set; }
    public List<Person> Attendees { get; set; }
}

This is a very simple class to define our meeting but it has no way of knowing if it has changed and also the StartTime property is stored on the server as UTC but the client could be anywhere.

 

Taking the latter problem first you may be tempted to bind directly to the StartTime property of this object and use a converter to convert to the appropriate time zone based on the user culture (as I have done many times).  As for the problem with a meeting change, there has to be some way of telling an object that it has changed.  Both of these problems can be solved with a MeetingViewModel.  This is a VM that follows the decorator pattern and could be implemented as follows:

public class MeetingViewModel
    {
        private Meeting inner;
        public MeetingViewModel(Meeting m)
        {
            inner = m;
        }

        public Meeting Inner
        {
            get
            {
                return inner;
            }
        }

        public string Location
        {
            get
            {
                return inner.Location;
            }
            set
            {
                inner.Location = value;
            }
        }
        public DateTime StartTime
        {
            get
            {
                return inner.StartTime;
            }
            set
            {
                inner.StartTime = value;
            }
        }
        public List<Person> Attendees
        {
            get
            {
                return inner.Attendees;
            }
            set
            {
                inner.Attendees = value;
            }
        }

        public DateTime LocalStartTime
        {
            get
            {
                return inner.StartTime.ToLocalTime();
            }
            set
            {
                inner.StartTime = value.ToUniversalTime();
            }
        }

        public bool IsDirty { get; set; }
    }

Here we now have a nice property that sorts out the StartTime into a local time for us and a property that determines if this object has changed.  In your VM that controls your view you now operate on an object of type MeetingViewModel and all bindings are to this object.  When it comes time to save the object you simply need to check if you have set the dirty flag and if so extract the internal Meeting object using the get-only property and send it back to the service.

 

This is also a nice way of working with business objects that you have no control over such as from an external web service or third party library.  Once you start to understand the power of this approach over simply using converters you will find yourself writing VM’s for all of your business objects that you need to modify slightly on the client side when you need properties like the above or other bits of information like calculated properties.

Using JustMock and Dependency Injection to mock data providers

Justmock is an excellent, fairly new, mocking framework from Telerik that I had the pleasure of getting a free licence for at the launch event.  The company I work for has now picked this up and is intending on rolling it out across the development department and I don’t think it can happen soon enough.  This is a conversation I have just had (edited and redacted for this blog) with a colleague about using it to mock up the fetching of data.

The current set up was similar to this much more contrived example but it serves to demonstrate the changes we made.

We had a class that depended on the data provider to access the database and return actual values to verify a method was working.  For this example I am using simple number checking but the actual problem was much larger.  The data provider fetches a list of numbers based on an initial value and then the checker returns the maximum value in the results set.  The data provider interface and checker are below.

public interface IDataProvider
{
    List GetNumbers(int start);
}

public class DataProvider : IDataProvider
{
    public List GetNumbers(int start)
    {
        var list = new List();
        // Use EF to access db and return list based on parameter
        // return a new list for this example
        return list;
    }
}

public class NumberChecker
{
    public int Getmax()
    {
        IDataProvider dp = new DataProvider();
        return dp.GetNumbers(5).Max();
    }

    public List GetNumbers()
    {
        IDataProvider dp = new DataProvider();
        return dp.GetNumbers(5);
    }
}

This is very simple code and the associated test went something like this.

[TestMethod()]
public void CheckCheckGeneratorReturnsMaximumValue()
{
    NumberChecker checker = new NumberChecker();
    int expected = checker.GetNumbers().Max();
    int actual = checker.Getmax();
    Assert.AreEqual(expected, actual);
}

This test passes but its not very nice.  It calls the generator methods twice and then continues to touch the database in order to get the data.

We really wanted to use JustMock so we broke it out and installed it on his machine.

To refactor this code into something testable we first had to remove that dependency on the data provider. The fact that it has an interface makes this much easier as we can simply inject an implementer of this interface into the method and act on that.  So without changing the implementation of the data provider and the interface the NumberChecker class became the following.

public class NumberChecker
{
    public int Getmax(IDataProvider dp)
    {
        return dp.GetNumbers(5).Max();
    }

    public List GetNumbers(IDataProvider dp)
    {
        return dp.GetNumbers(5);
    }
}

Here we have moved the data provider up to a parameter and are now able to inject any implementer we choose into this method.

This now allows us to test these methods without accessing the data or the real data provider (as we are not testing that here).

JustMock has a method that allows you to return any value when calling a method on a mocked object (Returns).  Using this we can mock up our data provider to do something that we want it to do rather than access the database.  This then allows us to return a custom value so the test now becomes:

[TestMethod()]
public void CheckCheckGeneratorReturnsMaximumValue()
{
    // ARRANGE
    // Create a new list of integers to use as the returns value
    var ints = new List { 1, 2, 3, 4, 5 };

    // Create the data provider object and set it up so that GetNumbers method
    // always returns the list we created above.
    var provider = Mock.Create();
    Mock.Arrange(() => provider.GetNumbers(Arg.IsAny<int>())).Returns(ints);

    // ACT
    // Run the NumberChecker method passing in our mocked data provider
    NumberChecker checker = new NumberChecker();
    int actual = checker.Getmax(provider);

    // ASSERT
    int expected = 5;
    Assert.AreEqual(expected, actual);
}

As we can now see passing in the data provider instance from here makes the test much easier to understand.  We have created a new list of integers and are simply returning this from the method on the data provider that we pass in to our NumberChecker.

Binding and styling text to a RichTextBox in WPF

The RichTextBox in WPF is a great tool for dealing with text that needs to be styled (such as syntax highlighting) but its not so great when it comes to allowing us to bind and edit text on the fly.

I got a feature request from our product manager to change the colour of certain text within a TextBox to match a legacy application.  It turns out it is not as straight forward as you might expect.

We have text in an SQL database like this:

this is a title:.\r\n\r\nThis is a normal line\r\n\r\nthis is another title:.\r\n

You can see that the titles end with “:.” so all we need to do is pull out these lines and make them (in my case) blue.

The problem is that this text is on an object that my previous TextBox was able to bind its Text property to with ease, but the RichTextBox has no text property as it displays a flow document. OK, I thought, I will just bind the text to the document as follows:

<RichTextBox IsReadOnly=”True” Document=”{Binding ElementName=ViewType, Path=SelectedItem.Tag />

This doesn’t work because the Document property is not a Dependency Property and therefore can not be bound to.  So BindableRichTextBox here I come.  I created a very simple control so that I could bind to the Document property.  In doing this I discovered that the Document property expects a FlowDocument as its content so I had to convert my text string to a flow document with the relevant parts highlighted.  I used a converter to spit out the FlowDocument with the correctly formatted text on a per line basis


public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    FlowDocument doc = new FlowDocument();

    string s = value as string;
    if (s != null)
    {
        using (StringReader reader = new StringReader(s))
        {
            string newLine;
            while ((newLine = reader.ReadLine()) != null)
            {
                Paragraph paragraph = null;
                if (newLine.EndsWith(":."))
                {
                    paragraph = new Paragraph(new Run(newLine.Replace(":.", string.Empty)));
                    paragraph.Foreground = new SolidColorBrush(Colors.Blue);
                    paragraph.FontWeight = FontWeights.Bold;
                }
                else
                {
                    paragraph = new Paragraph(new Run(newLine));
                }

                doc.Blocks.Add(paragraph);
            }
        }
    }

    return doc;
}

This simply takes the string and reads it line by line.  If we have the desired characters at the end of a line (“:.”) then we make the line blue and bold and remove the characters, otherwise we just add the text.  Each line is added as a paragraph so to reduce the space between each one I added the following to the control declaration in the XAML

<RichTextBox.Resources>

<Style TargetType=”{x:Type Paragraph}”>

<Setter Property=”Margin” Value=”0″/>

</Style>

</RichTextBox.Resources>

This simply removes the the margin from each paragraph.

The final part of the puzzle is the control that allows binding this is a simple case of adding a dependency property onto a new control that inherits from RichTextBox

public class BindableRichTextBox : RichTextBox
{
    public static readonly DependencyProperty DocumentProperty = DependencyProperty.Register("Document", typeof(FlowDocument), typeof(BindableRichTextBox), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnDocumentChanged)));

    public new FlowDocument Document
    {
        get
        {
            return (FlowDocument)this.GetValue(DocumentProperty);
        }

        set
        {
            this.SetValue(DocumentProperty, value);
        }
    }

    public static void OnDocumentChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        RichTextBox rtb = (RichTextBox)obj;
        rtb.Document = (FlowDocument)args.NewValue;
    }
}

I hope you find a use for this – I simply need it written down somewhere so I don’t forget!