Silverlight sparkline chart

According to Wikipedia

A sparkline is a very small line chart, typically drawn without axes or coordinates.

Though this chart is not included by default to the Silverlight Toolkit library, it is very easy to implement such chart by styling the built-in Line chart. Here is an example which I’ve implemented:

silverlight_sparkline_sample

At first I’ve changed the default control template of the Chart control, I’ve removed all paddings, the chart title, and reduced the minimum height and width of the chart. Also I’ve changed the DataPoint template (made them invisible) and the Polyline template (reduced its thickness). Here is the XAML code:

<UserControl.Resources>
    <Style x:Key="ChartWithoutPaddings" TargetType="chart:Chart">
        <Setter Property="Padding" Value="0" />
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="ChartAreaStyle">
            <Setter.Value>
                <Style TargetType="Panel">
                    <Setter Property="MinWidth" Value="100" />
                    <Setter Property="MinHeight" Value="20" />
                </Style>
            </Setter.Value>
        </Setter>
        <Setter Property="PlotAreaStyle">
            <Setter.Value>
                <Style TargetType="Grid">
                    <Setter Property="Background" Value="Transparent" />
                </Style>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="chart:Chart">
                    <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
                        <chartingprimitives:EdgePanel x:Name="ChartArea" Style="{TemplateBinding ChartAreaStyle}">
                            <Grid Canvas.ZIndex="-1" Style="{TemplateBinding PlotAreaStyle}" />
                        </chartingprimitives:EdgePanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style x:Key="EmptyDataPoint" TargetType="Control">
        <Setter Property="Background" Value="Black" />
        <Setter Property="Template" Value="{x:Null}" />
    </Style>

    <Style x:Key="OnePixelLine" TargetType="Polyline">
        <Setter Property="StrokeThickness" Value="1" />
    </Style>
</UserControl.Resources>

This code is almost all that you need to create a sparkline chart. All that is left is to remove axes. It wasn’t a trivial thing, so I used some kind of a hack: I set their width (for Y axis) and height (for X axis) to zero.

<chart:Chart Style="{StaticResource ChartWithoutPaddings}">
    <chart:LineSeries ItemsSource="{Binding FirstIndexItems}" IndependentValuePath="Number" DependentValuePath="Value" 
                        DataPointStyle="{StaticResource EmptyDataPoint}" 
                        PolylineStyle="{StaticResource OnePixelLine}"  />
    <chart:Chart.Axes>
        <chart:LinearAxis Orientation="X" Height="0" Opacity="0" />
        <chart:LinearAxis Orientation="Y" Width="0" Opacity="0" />
    </chart:Chart.Axes>
</chart:Chart>

Links
Source code: SparklineChartSample.zip
Showcase: SparklineChartSampleTestPage.html

Silverlight and WP7 chart with data point labels

Recently I found the question on stackoverflow in which one user asked how to add labels to data points on WPF/Silverlight/Windows Phone Toolkit charts. Whereas almost every javascript chart can do this, this functionality is absent in Silverlight charts and none of developers cares.

So I wrote a simple class which extended the LinearSeries class and now line charts can be displayed like this:

silverlight_chart_datapointlabels

wp7_chart_datapointlabels

I added labels only for line charts, but if someone needs them for column charts, I can try to implement it as well.
In the current implementation I created the class which inherits the LineSeries class. It has the following properties:
DisplayLabels – You should set it to true explicitly so that labels are displayed. It is false by default.
LabelBindingPath – Optional. You can specify a custom property of your model which will be displayed instead of the value from the Y-axis.
LabelStyle – Optional. You can change foreground, font weight, font size and other properties of labels.

The example of usage:

<chart:Chart Width="600" Height="300">
    <local:ExtendedLineSeries
        ItemsSource="{Binding Items}"
        DependentValuePath="ItemValue"
        IndependentValuePath="Title" 
        DisplayLabels="True"
        LabelBindingPath="ItemValue" />
</chart:Chart>

The complete source code of the class:

public class ExtendedLineSeries : LineSeries
{
    private Canvas _labelsCanvas;
    private Dictionary<DataPoint, TextBlock> _currentLabels = new Dictionary<DataPoint, TextBlock>();

    /// <summary>
    /// Gets or sets a value indicating whether labels should be displayed. 
    /// </summary>
    public bool DisplayLabels { get; set; }

    /// <summary>
    /// Gets or sets the binding path of the label.
    /// </summary>
    public string LabelBindingPath { get; set; }

    /// <summary>
    /// Gets or sets the style of each label.
    /// </summary>
    public Style LabelStyle { get; set; }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        // get a canvas to which the labels will be added
        this._labelsCanvas = (Canvas)this.GetTemplateChild("PlotArea");
        // clear the clip property so that labels are visible even if they exceed the bounds of the chart
        this.Clip = null;
    }

    protected override void UpdateDataPoint(DataPoint dataPoint)
    {
        base.UpdateDataPoint(dataPoint);

        // after the data point is created and added to the chart, we can add a label near it
        if (this.DisplayLabels && dataPoint.Visibility == System.Windows.Visibility.Visible)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => this.CreateLabel(dataPoint));
        }
    }

    private void CreateLabel(DataPoint dataPoint)
    {
        // this method is also called with the SizeChanged event, so I create the label only one time
        TextBlock label;
        if (this._currentLabels.ContainsKey(dataPoint))
        {
            label = this._currentLabels[dataPoint];
        }
        else
        {
            label = new TextBlock();
            this._labelsCanvas.Children.Add(label);
            this._currentLabels.Add(dataPoint, label);

            label.Style = this.LabelStyle;

            // bind the label text to the specified path, or to dataPoint.DependantValue by default
            Binding binding = this.LabelBindingPath != null
                        ? new Binding(this.LabelBindingPath) { Source = dataPoint.DataContext }
                        : new Binding("DependentValue") { Source = dataPoint };
            BindingOperations.SetBinding(label, TextBlock.TextProperty, binding);
        }

        // calculate a position of the label
        double coordinateY = Canvas.GetTop(dataPoint) - label.ActualHeight; // position the label above the data point
        double coordinateX = Canvas.GetLeft(dataPoint) + dataPoint.ActualHeight / 2 - label.ActualWidth / 2; // center horizontally
        Canvas.SetTop(label, coordinateY);
        Canvas.SetLeft(label, coordinateX);
    }
}

In this code I made an override of the UpdateDataPoint method and each time a DataPoint is updated I update its label.
The code work with Silverlight as well as with Windows Phone 7. For WP7 I used the recompiled library which I published in one of my previous posts.

Source code of the sample application: ChartPointLabelsSample.zip
Show case: ChartPointLabelsSampleTestPage.html

Highlight found text in ListBox for Silverlight and WP7

You probably saw an implementation of search where all matches of the entered query were highlighted in the text or list, or table. Here are 2 screenshots which illustrate the described functionality:

It is very easy to implement in Javascript, just 4 lines:

var html = element.html();
html = html.replace(new RegExp("<span class=\"highlighted\">(.*?)<\/span>", "i"), "$1"); // clear the previous highlight
html = html.replace(new RegExp("(" + query + ")", "i"), "<span class=\"highlighted\">$1</span>"); // highlight the current search query
element.html(html);

But it is slightly more difficult in Silverlight. However the approach is the same:
1. Get the text value.
2. Replace some places in the text by a span with some user-defined style.
3. Parse the result text and display it.

I have created a new project by using the Windows Phone Databound Application template in Visual Studio, so that I don’t need to create base mark-up and add default data, Visual Studio creates everything by itself.

At first, we need to write methods which replace values of ListBox by formatted values. The corresponding javascript code is `html.replace(new Regexp(…))`. The C# code looks so:

public void Search()
{
    this.ClearHighlights();

    if(string.IsNullOrEmpty(SearchQuery))
    {
        return;
    }

    this.AddHighlights();
}

private void ClearHighlights()
{
    var highlightRegex = new Regex("<Run Foreground='Yellow'>(.*?)</Run>");
    foreach (var item in this.Items)
    {
        item.LineOne = highlightRegex.Replace(item.LineOne, "$1");
        item.LineTwo = highlightRegex.Replace(item.LineTwo, "$1");
    }
}

private void AddHighlights()
{
    var searchRegex = new Regex(string.Format("({0})", this.SearchQuery), RegexOptions.IgnoreCase);
    foreach (var item in this.Items)
    {
        item.LineOne = searchRegex.Replace(item.LineOne, "<Run Foreground='Yellow'>$1</Run>");
        item.LineTwo = searchRegex.Replace(item.LineTwo, "<Run Foreground='Yellow'>$1</Run>");
    }
}

The `LineOne` and `LineTwo` properties contain some strings which are displayed in each item of the ListBox.

Finally, we need to write a binding which correctly displays a text with the `Run` tags. The corresponding javascript code is `elem.html(html)`. I used attached property for this task:

public static class TextBlockProperties
{
    public static string GetStyledText(DependencyObject obj)
    {
        return (string)obj.GetValue(StyledTextProperty);
    }

    public static void SetStyledText(DependencyObject obj, string value)
    {
        obj.SetValue(StyledTextProperty, value);
    }

    public static readonly DependencyProperty StyledTextProperty =
        DependencyProperty.RegisterAttached("StyledText", typeof(string), typeof(TextBlock), new PropertyMetadata(null, StyledText_Changed));


    private static void StyledText_Changed(DependencyObject d, DependencyPropertyChangedEventArgs args)
    {
        var tb = (TextBlock) d;
        var text = (string) args.NewValue;

        if(string.IsNullOrEmpty(text) || !Regex.IsMatch(text, "<Run.*?>.*?</Run>"))
        {
            tb.Text = text;
            return;
        }

        var formattedTextBlockXaml = "<TextBlock xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>" + text + "</TextBlock>";
        var formattedTextBlock = (TextBlock) XamlReader.Load(formattedTextBlockXaml);

        // detach parsed inlines from the view tree
        var inlines = formattedTextBlock.Inlines.ToList();
        formattedTextBlock.Inlines.Clear();

        // add inlines to the specified text block
        tb.Inlines.Clear();
        foreach (var inline in inlines)
        {
            tb.Inlines.Add(inline);
        }
    }
}

So now all that you need is to use the StyledText property instead of Text:

<TextBlock ext:TextBlockProperties.StyledText="{Binding LineOne}" />

In my example I used the yellow color for highlighting, but you can change any property of the `Run` class, like FontWeight (Bold), FontStyle (Italic) and others, the list of properties you can find here: Run Class.

The sample application which I used in order to make the 2 screenshots above you can download here: Wp7ListSearchSample.zip

Updated BindableTabControl post

It is an update to this post.

In that post I implemented the extended TabControl which supported data binding, however it had one inconvenience that it didn’t allow to access and customize its TabItems. Personally me, I have never used TabItems, but it happened that one guy needed to change the Visibility property of specific items, here is his comment. So he added some code to my class and send it to me.

If you use the control from the original post, XAML code will look like this:

<local:ExtendedTabControl 
    ItemsSource="{Binding}" 
    ItemTemplate="{StaticResource ExampleHeaderTemplate}" 
    ContentTemplate="{StaticResource ExampleContentTemplate}" />

Now you can use the third property TabItemTemplate and write your code so:

<local:ExtendedTabControl ItemsSource="{Binding}">
	<local:ExtendedTabControl.TabItemTemplate>
		<DataTemplate>
			<controls:TabItem Visibility="{Binding Visibility}" HeaderTemplate="{StaticResource ExampleHeaderTemplate}" ContentTemplate="{StaticResource ExampleContentTemplate}" />
		</DataTemplate>
	</local:ExtendedTabControl.TabItemTemplate>
</local:ExtendedTabControl>

The first code is enough in most cases, but if you want to use some properties of the TabItem class like Visibility, Style, Template, it is preferrable to use the second code.

The source code of the updated control is available here.

Working with JSON web services in Silverlight and Windows Phone 7

In this post I’ll explain how to retrieve and display data from JSON web services.

As an example I’ll use the REST service from geonames.org.

JSON response of the example looks so:

At first, you should create C# classes (models) which can be mapped to JSON entities.
The first curly braсe indicates that it is an object, and it has 1 property `geonames`. After this property you can see the square bracket indicating an array. This array consists of many objects, and each object has 12 properties.
So we should create a model for the root object, which looks so:

// { geonames: [{}, {}, {}] }
[DataContract]
public class CitiesList
{
	[DataMember(Name = "geonames")]
	public List<City> Cities { get; set; }
}

It is important to add DataContract and DataMember attributes to the class and all its properties. Also you should specify the name of the corresponding JSON property (geonames) inside the DataMember attribute.

Then we should create the model for inner objects (cities). As you already saw, each JSON object has 12 properties, but we don’t need all of them. So we can specify only those proeprties which we need, and .Net deserializer will ignore all other properties.

// { name: "", countrycode: "", population: -1 }
[DataContract]
public class City
{
	[DataMember(Name = "name")]
	public string Name { get; set; }

	[DataMember(Name = "countrycode")]
	public string CountryCode { get; set; }

	[DataMember(Name = "population")]
	public int Population { get; set; }
}

So now all that you need is to create an instance of the HttpWebRequest class, get the response and deserialize it by using the DataContractJsonSerializer class. The deserializer requires the System.Servicemodel.Web and System.Runtime.Serialization references.

You must use the two following methods to perform loading and parsing of JSON.

private void BeginDownloadCitiesRequest()
{
	// create the http request
	HttpWebRequest httpWebRequest = WebRequest.CreateHttp("http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=en&username=vortexwolf");
	httpWebRequest.Method = "GET";
	httpWebRequest.Accept = "application/json";

	// get the response asynchronously
	httpWebRequest.BeginGetResponse(OnGetResponseCompleted, httpWebRequest);
}

private void OnGetResponseCompleted(IAsyncResult ar)
{
	var httpWebRequest = (HttpWebRequest)ar.AsyncState;

	// get the response
	var response = httpWebRequest.EndGetResponse(ar);

	// deserialize json
	var jsonSerializer = new DataContractJsonSerializer(typeof(CitiesList));
	var responseObject = (CitiesList)jsonSerializer.ReadObject(response.GetResponseStream());

	// display on the view
	Deployment.Current.Dispatcher.BeginInvoke(() => OnCitiesDownloaded(responseObject));
}

The code of creating a http request and getting a response will often repeat in different places of the application, so it is preferrable to move this code to a separate class.
I did it so:

public class HttpGetTask<T>
{
    public HttpGetTask(string url, Action<T> onPostExecute)
    {
        this.Url = url;
        this.OnPostExecute = onPostExecute;
    }

    public void Execute()
    {
        if (this.OnPreExecute != null)
        {
            this.OnPreExecute();
        }

        // create the http request
        HttpWebRequest httpWebRequest = WebRequest.CreateHttp(this.Url);
        httpWebRequest.Method = "GET";
        httpWebRequest.Accept = "application/json";

        // get the response asynchronously
        httpWebRequest.BeginGetResponse(OnGetResponseCompleted, httpWebRequest);
    }

    private void OnGetResponseCompleted(IAsyncResult ar)
    {
        var httpWebRequest = (HttpWebRequest)ar.AsyncState;

        // get the response
        HttpWebResponse response;
        try
        {
            response = (HttpWebResponse)httpWebRequest.EndGetResponse(ar);
        }
        catch (WebException)
        {
            this.InvokeOnErrorHandler("Unable to connect to the web page.");
            return;
        }
        catch (Exception e)
        {
            this.InvokeOnErrorHandler(e.Message);
            return;
        }

        if (response.StatusCode != HttpStatusCode.OK)
        {
            this.InvokeOnErrorHandler((int)response.StatusCode + " " + response.StatusDescription);
            return;
        }

        // response stream
        var stream = response.GetResponseStream();

        // deserialize json
        var jsonSerializer = new DataContractJsonSerializer(typeof(T));
        var responseObject = (T)jsonSerializer.ReadObject(stream);

        // call the virtual method
        this.InvokeInUiThread(() => this.OnPostExecute(responseObject));
    }

    private void InvokeOnErrorHandler(string message)
    {
        if (this.OnError != null)
        {
            this.InvokeInUiThread(() => this.OnError(message));
        }
    }

    private void InvokeInUiThread(Action action)
    {
        Deployment.Current.Dispatcher.BeginInvoke(action);
    }

    public string Url { get; private set; }

    public Action<T> OnPostExecute { get; private set; }

    public Action OnPreExecute { get; set; }

    public Action<string> OnError { get; set; }
}

You can execute this task by specifying Url and the OnPostExecute callback. Also you can set other properties. Example:

public class MainViewModel : INotifyPropertyChanged
{
    public MainViewModel()
    {
        Cities = new ObservableCollection<CityViewModel>();

        string url = "http://api.geonames.orgzz/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=en&username=vortexwolf";
        
        var task = new HttpGetTask<CitiesList>(url, this.OnPostExecute);
        task.OnPreExecute = this.OnPreExecute;
        task.OnError = this.OnError;

        task.Execute();
    }

    private void OnPreExecute()
    {
        this.IsLoading = true;
    }

    private void OnPostExecute(CitiesList responseObject)
    {
        this.OnCitiesDownloaded(responseObject);
        this.IsLoading = false;
    }

    private void OnError(string message)
    {
        MessageBox.Show(message);
        this.IsLoading = false;
    }

    public ObservableCollection<CityViewModel> Cities { get; set; }

    private bool _isLoading;

    public bool IsLoading
    {
        get { return _isLoading; }
        set
        {
            _isLoading = value;
            RaisePropertyChanged("IsLoading");
        }
    }

    private void OnCitiesDownloaded(CitiesList citiesList)
    {
        var cityModels = citiesList.Cities
            .Select(c =>
                    new CityViewModel
                    {
                        Name = c.Name,
                        CountryCode = c.CountryCode,
                        Population = c.Population
                    })
            .ToList();

        cityModels.ForEach(this.Cities.Add);
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

I created the sample application for Windows Phone 7 which retrieves JSON data and displays it on the phone.

The source code of the example you can download here: https://dl.dropbox.com/u/8047386/WordPress/PhoneJsonTest.zip

Silverlight and WPF Timeline Scroll View

Here is another control which I had for a long time but only recently have decided to arrange the source code and post it here.
That’s how it looks:

Although it looks very complex, actually it is quite simple: it is just the styled ScrollBar control on the left and the ScrollViewer on the right.

The grey control with years on the left is the UserControl called TimelineScrollBar, mark-up of which looks so:

<Grid>
	<ItemsControl x:Name="rowItems">
		<ItemsControl.ItemTemplate>
			<DataTemplate>
				<Grid Height="{Binding Height}">
					<TextBlock Text="{Binding Text}"/>
				</Grid>
			</DataTemplate>
		</ItemsControl.ItemTemplate>
	</ItemsControl>

	<!-- ... -->

	<ScrollBar x:Name="VerticalScrollBar" Style="{StaticResource TimeLineScrollBarStyle}" />
</Grid>

The rowItems items control and the VerticalScrollBar scroll bar are related to the dependency properties TimeItemsSource and BoundScrollviewer which should be set outside and are handled in the code-behind:

<Views:TimelineScrollBar x:Name="timelineScroller" 
 TimeItemsSource="{Binding TimelineItems}" 
 BoundScrollViewer="{Binding ElementName=listScroller}" 
 Width="120" />

The TimelineItems is the special collection of items { Text, Height}. These properties must be present and they are quite generic, so you can use any labels instead of years.

The generation of these items is the most difficult part, after that everything is quite easy.

Create the view model:

public class MainViewModel
{
	public List<TestItemViewModel> Items { get; private set; }

	public List<TimelineItemViewModel> TimelineItems { get; private set; }
}

Set is as DataContext to the view:

<Grid>
	<Views:TimelineScrollBar x:Name="timelineScroller" 
 TimeItemsSource="{Binding TimelineItems}" 
 BoundScrollViewer="{Binding ElementName=listScroller}" 
 Width="120" />

	<ScrollViewer x:Name="listScroller">
		<ItemsControl x:Name="list" ItemsSource="{Binding Items}" ItemTemplate="{StaticResource itemTemplate}" ItemsPanel="{StaticResource itemsControlTemplate}" />
	</ScrollViewer>
</Grid>

In this example I used the ItemsControl class for simplicity. If you want to use it with the ListBox class, you should change its ControlTemplate and retrieve the name of the inner ScrollViewer control so it can be bound to the timeline scroll bar.

The source code of my example you can download here: TimeScrollViewerSample.zip

Silverlight show case: TimeScrollViewerSampleTestPage.html

Silverlight Chart with reversed Y axis

Recently on StackOverflow.com I’ve found a question about Silverlight charts:
“Is it possible to display a Y LinearAxis in Silverlight in reversed order? Instead of lower numbers at the bottom increasing to the top of the Y axis, I would like to see lower numbers at the top”.

I can’t imagine where such chart can be used, maybe to display a bad revenue report in the best possible way. The chart on the right looks much better than the left one.

two linear charts comparison

Anyway after lot of efforts I’ve managed to create such axis without changing the source code of the Toolkit library, just by using the inheritance so that you can use it so:

<chart:Chart>
	<cr:ReversedAxisColumnSeries ItemsSource="{Binding Items}" DependentValuePath="Value" IndependentValuePath="Title" />
	<cr:ReversedAxisLineSeries ItemsSource="{Binding Items}" DependentValuePath="Value" IndependentValuePath="Title" />
	<chart:Chart.Axes>
		<cr:ReversedLinearAxis Orientation="Y" />
	</chart:Chart.Axes>
</chart:Chart>

Here is links to the solution and inside the post I’ll describe how I’ve implemented these classes.
Source code: ChartReversedAxisSample.zip
Showcase: TestPage.html
Read more of this post

The necessity of a ViewModel class for each Model class

It is well known that you need a ViewModel if you want to add property change notification or validation to a Model. But what if the Model and ViewModel classes don’t differ at all? Should you create a ViewModel class if it has the same set of properties that the Model class has? The answer is yes, absolutely. The brief reasons are separation of layers and loose coupling. But I know that these abstract terms don’t sound very convincing so I’ll describe my point of view more particularly in this post.

As an example I’ll use this data source class (which can be either a web service, or a database, or a file, whatever) and this model:

public interface IModelSource
{
    SettingsModel GetSettings();
}

public class SettingsModel
{
    public string DefaultPage { get; set; }

    public string DownloadsFolder { get; set; }

    public bool AutoStart { get; set; }
}

So we should choose which approach to use.
Just to bind the model as it is:

SettingsModel model = source.GetSettings();
this.DataContext = model;

Or to use the extra ViewModel layer and convert the model before binding:

SettingsModel model = source.GetSettings();
SettingsViewModel viewModel = ConvertModelToViewModel(model);
this.DataContext = viewModel;

Let’s examine some cases and look at the differences between the approaches above.

 

1. Remove a property from the model class.
It happens quite often during development, this type of changes can be performed on the service side or in the database. So if to remove the AutoStart property, what will happens then?

The model-only approach
You will not be aware of the error and will not notice it until you run your application, navigate to the corresponding view and look at the Output window. There among messy messages you will see the notification about the binding error:
Runtime binding error
Also you should run your application in the Debug mode. If you start it by using the Ctrl+F5 combination, you will never find the error.

The viewmodel approach
You will be notified about the error almost immediately before you run the application. And you know: the earlier the bug is found – the easier to fix it.

 

2. Add a property of a complicated data type to the model class.
For example, this property of the Enum type:

NumberFormatCulture NumberFormat { get; set; }

The model-only approach
It isn’t clear how to bind this enum to the ComboBox control (I think, you will not display such programming language related values as “EnglishUS” to end users, won’t you?), so you’ll search it on Google or StackOverflow and eventually you’ll choose either a hacky solution (which will work only for the particular case) or you’ll agree to use the ViewModel (and admit wasting the time).

The viewmodel approach
Just add a few lines to the mapping configuration which can be easily bound to the ComboBox:

//Mapper.CreateMap ... 
.ForMember(vm => vm.NumberFormats, option => option.UseValue(
    EnumExtensions.GetValues<NumberFormatCulture>().Select(TranslateEnum)))
.ForMember(vm => vm.SelectedNumberFormat, option => option.MapFrom(
    m => TranslateEnum(m.NumberFormat)))

 

3. Change the structure of the model class.
For example, if to change some property of the string type to the property of another model type:

public PageModel DefaultPage { get; set; }

public class PageModel
{
    public string Url { get; set; }
}

The model-only approach
Again, you will not notice the error until you run the application and look at the Ouput Window (see p.1). Then you should run over all the xaml-markup in the view and correct bindings. And of course launch the application once again to assure that everything is fine after the changes.

The viewmodel approach
Just fix one line of the code in the mapping configuration:

//Mapper.CreateMap ... 
.ForMember(vm => vm.DefaultPage, option => option.MapFrom(m => m.DefaultPage.Url))

I must say that in this case the mapper doesn’t perform compile-time checking, but you can configure it so that it throws an exception if you try to map from the object type to the string type. And exceptions are any easier to notice and understand than debug messages in the Output window.

 

4. Project structure and maintenability
It isn’t a big advantage of the viewmodel approach in comparison with the above described points, but anyway, it is much better to have a good project structure when each view has a corresponding view model with the same class name prefix. You will not search which model class is bound to, for example, the SettingsView class (which model class: UserSettingsModel, ServiceSettingsModel? I don’t remember so I’ll take some time to find it out). You’ll just open the folder with view models and immediately see the corresponding SettingsViewModel class.

 

The most popular exuse not to create the extra layer is because it allegedly takes much time. But if to calculate the exact amount, the statement will be far from the truth.
- Add the AutoMapper library by using the NuGet package manager – 20 second (this task is performed only once)
- Create a new ViewModel class and just copypaste all of the properties of the model – 30 seconds
- Configure the mapping by using code-snippets – 5 seconds per property.

So it’ll take something about 1-2 minutes to create a ViewModel and I can’t say that it is a “huge amount of time”. And this amount is nothing in comparison with the time wasted on the above described points if to use the wrong approach. Don’t afraid to spend few minutes now, it will save many hours in the future.

WPF and Silverlight design patterns

In this post I’ll describe the design patterns which are used in large and complex applications in order to simplify their development and maintenance.

Model View ViewModel
Separates Model and View by introducing the intermediate layer which is called ViewModel. It is a some kind of a “super converter” which adds additional properties and behavior to the model. Also commonly used as a replacement of code-behind.
The most common features of ViewModel:

  • Property changes notification with the INotifyPropertyChanged interface
  • Validation with the IDataErrorInfo or INotifyDateErrorInfo interfaces
  • Event handling of View events
  • Invocation of WCF services
  • Converting of model properties from one data type to another

Example of Model and ViewModel:

public class UserModel
{
	public string Name { get; set; }
}

public class UserViewModel : IDataErrorInfo, INotifyPropertyChanged
{
	private string name;

	public string Name
	{
		get { return name; }
		set
		{
			name = value;
			RaisePropertyChanged(&quot;Name&quot;);
		}
	}

	public ICommand ChangeNameCommand { get; set; }

	public string Error
	{
		get { throw new NotImplementedException(); }
	}

	public string this[string columnName]
	{
		get { return this._validator.GetErrors(columnName).FirstOrDefault(); }
	}

	public event PropertyChangedEventHandler PropertyChanged;

	private void RaisePropertyChanged(string propertyName)
	{
		if (this.PropertyChanged != null)
			this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
	}
}

Links:
Wikipedia. Model View ViewModel
Developer’s Guide to Microsoft Prism. Implementing the MVVM Pattern
Never In Doubt: MVVM Backlash

 

Dependency Injection
The purpose of this pattern is to get rid of using of external classes and to use interfaces instead.
This pattern adds the following benefits:

  • Allows to write unit tests because interfaces can be replaced by “fake” classes
  • Allows to change one interface implementation by another without affecting or changing existing objects

For example, this class:

public class MyViewModel
{
	public MyViewModel()
	{
		this.SomeProperty = Resources.String1; // the static class call
	}

	public void Refresh()
	{
		var model = new MyWcfServiceClient().GetModelById(this.Id); // the service creation

        // initialize the corresponding properties of the view model
	}
}

should be rewritten so:

public class MyViewModel
{
	public MyViewModel(IResourceManager resourceManager, IServiceClient serviceClient)
	{
		this._resourceManager = resourceManager;
		this._serviceClient =  serviceClient;

		this.SomeProperty = this._resourceManager.String1;
	}

	public void Refresh()
	{
		var model = this._serviceClient.GetModelById(this.Id);

        // initialize the corresponding properties of the view model
	}
}

Links:
Wikipedia. Dependency injection
MSDN Magazine. Design Patterns: Dependency Injection

 

Modular Application
This concept is based on the logical division of application components and if you use several projects with different functionality, you already use a some kind of modules. For example, if your solution has projects like Application.Mail, Application.Calendar, Application.Tasks – it has 3 modules as well.

Besides the above mentioned logical division, the Prism framework adds the following features:

  • Allows to add modules after the application is released (some kind of plug-ins)
  • Allows to defer module loading and load some of them on demand

Links:
Developer’s Guide to Microsoft Prism. Modular Application Development

 

Event Aggregator
This pattern is known as Messenger in the MVVM Light Toolkit. Implements the “publish-subscribe” model. For example, if one view model should call a method of another view model, it can be done by using two ways:
1. Bad practice: The first view model gets the second view model as the constructor parameter and then calls the necessary methods directly by using the code like this._otherModel.OnUserUpdated(this).
2. The preferred approach: The second view model publishes an event, the first one subscribes to it and handles appropriately.

Links:
Martin Fowler. Event Aggregator
Developer’s Guide to Microsoft Prism. Communicating Between Loosely Coupled Components

 

Command
Allows to get rid of the code-behind and handle button clicks inside a view model. Also it is useful when the same action is invoked from the application menu, context menu, toolbar and buttons, so you don’t need to write separate event handlers and you can use just a single command everywhere.
Besides the method invocation, commands in WPF affects the IsEnabled property of buttons and menu items as well: if a command can’t be executed, all the invoke buttons will be disabled.

Links:
Wikipedia. Command pattern
MSDN. Commanding QuickStart

WPF and Silverlight Validation with IDataErrorInfo and INotifyDataErrorInfo

In this post I’ll describe how to use the IDataErrorInfo and INotifyDataErrorInfo interfaces to perform validation in WPF and Silverlight.
There are several kinds of validations and the preferrable approach in the MVVM pattern is using the IDataErrorInfo or INotifyDataErrorInfo interface.
But this approach doesn’t behave as expected: it performs validation immediately after the launch of the view, whereas it would be better if the validation started only after a user has changed values. Also I would like to reuse some commonly used rules.

So I’ve created the helper class which performs all the necessary work. This class is similar to the class from the FluentValidation library, but it has less code and more flexible to me.
Here is the example of such validation:

    public class PersonViewModel : IDataErrorInfo, INotifyPropertyChanged
    {
        private ModelValidator _validator = new ModelValidator();

        public PersonViewModel()
        {
            //Six validation rules
            this._validator.AddValidationFor(() => this.FirstName).NotEmpty()
				.Show("Enter a First Name");
            this._validator.AddValidationFor(() => this.LastName).NotEmpty()
				.Show("Enter a Last Name");

            this._validator.AddValidationFor(() => this.Age).NotEmpty()
				.Show("Enter an age");
            this._validator.AddValidationFor(() => this.Age).Between(0,99)
				.Show("The age must be between 0 and 99");

            this._validator.AddValidationFor(() => this.Email)
				.When(() => this.IsSubscribe).NotEmpty()
				.Show("Enter an email address");
            this._validator.AddValidationFor(() => this.Email)
				.When(() => this.IsSubscribe).EmailAddress()
				.Show("Enter a valid email address");
            //Validates on changes of properties
            this.PropertyChanged += (s, e) => this._validator.ValidateProperty(e.PropertyName);
        }

        public string Error
        {
            get { throw new NotImplementedException(); }
        }

        public string this[string columnName]
        {
            get { return this._validator.GetErrors(columnName).FirstOrDefault(); }
        }

There is only 4 steps:
1. Create a variable of the ModelValidator type
2. Add necessary validation rules
3. Update validation every time when a property has been changed
4. Return cached errors inside the indexer property.

Actually it is not so obligatory to implement the 3rd step and update validation inside the PropertyChanged event handler. You can remove that line and call the ValidateAll method after a user clicks the Save button. But validation on changes is more preferrable solution.

I’ve added some predefined validation rules, if they aren’t enough, you can use the Must method with your own functions.
1. NotNull – the property value shouldn’t be null.
2. NotEmpty – if the property is of the string type, checks whether the string is null or consists of whitespaces. If of any other type – this rule is the same as NotNull.
3. Between – checks whether the property value is within a specific range. Works with strings as well as with numbers, so it’s not necessary to parse strings in view models.
4. EmailAddress – if the string value isn’t null, it should be a valid e-mail address.
5. Must – any user-defined validation function. For example: this._validator.AddValidationFor(() => this.LastName).Must(() => this.LastName.Length < 10).Show("Last name should not exceed 10 characters");

To implement this validation, you should copy 3 files with 2 classes to your project.
Here is the completed project where you can take all the necessary classes: http://dl.dropbox.com/u/8047386/WordPress/WpfValidation.zip

Update
I’ve also added the validation for Silverlight both with IDataErrorInfo and INotifyDataErrorInfo:
The image illustrating validation errors in Silverlight
The source code you can download here: SilverlightValidation.zip
Showcase: INotifyDataErrorInfoSampleTestPage.html

Follow

Get every new post delivered to your Inbox.