The Story So Far
Each of my previous blog items on WPF ListViews has mostly used a collection of DrinkProduct objects as the data source. This collection is bound to the Window via a DataContext and the individual columns are bound to fields in the collection. (As an alternative, this blog looked at the XML data source alternative.)
As the route from that first ListView blog to this one has become a bit murky, I'm going to start off by recreating the DrinkProduct class and creating the collection. I've taken the opportunity to add a few new properties which will be used in this and the upcoming ListView blogs.
You can view the revised DrinkProducts class code here.
The XAML markup for the start state of the ListView is in two locations. The ListView itself is in a WPF Window:
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WPF ListView" Height="300" Width="450">
<Grid>
<ListView Name="ProductsListView"
ItemsSource="{Binding}"
Margin="5" >
<ListView.View>
<GridView>
<GridViewColumn
HeaderTemplate="{StaticResource IDColHeader}"
CellTemplate="{StaticResource IDCellTemplate}">
< span>GridViewColumn>
<GridViewColumn
HeaderTemplate="{StaticResource NameColHeader}"
CellTemplate="{StaticResource NameCellTemplate}">
< span>GridViewColumn>
<GridViewColumn
HeaderTemplate="{StaticResource PackageColHeader}"
CellTemplate="{StaticResource PackCellTemplate}">
< span>GridViewColumn>
< span>GridView>
< span>ListView.View>
< span>ListView>
< span>Grid>
< span>Window>
All the Resources - GradientBrush, Styles, DataTemplates for ColumnHeaders and Cells - are in the Application.xaml file. You can see the markup for these here.
If the Resources looks like a lot of markup, it breaks down into much less if you analyze it. There's a GradientBrush, a couple of Styles, then the DataTemplates, which are really only slightly tweaked versions of two simple templates.
At this stage the ListView looks like this:

ValueConverters
In this blog I want to demonstrate a simple example of the creation and use of a ValueConverter in WPF. ValueConverters are particularly useful in situations where you are using data binding to directly populate elements in the UI. By definition, this means that the data from the fields of the data source are passed untested from the source to the display.
This data will often be in a raw state, e.g. primitive types such as integer, double, boolean, etc. In the first example I will use integer values that represent the quantity of stock remaining of the various drink products. These will be displayed in a new column of the ListView.
Although the DataTemplates created earlier can alter the core properties of all the values in the column - Foreground, Bold font, etc,- they don't offer any mechanism for analyzing these values and changing the look of the display of an individual value based on some criteria. For instance, changing the color of the text if the value is negative.
The way to achieve this kind of fine tuning is to use a ValueConverter. This automatically intercepts the data as it is being fed in from the DataContext, analyzes the value and makes any appropriate settings or changes to the display of this piece of data.
A Simple ValueConverter
Let's start with something simple, a ValueConverter that analyzes the quantity held in stock and if that value is less than a particular threshold, the figure is displayed in red in the ListView. This will give an easy introduction to the steps involved.
Before getting round to the ValueConverter I need to add a new column to the ListView, the column that will display the quantities held in stock. First a couple of DataTemplates - one for the column header and for the cell:
<DataTemplate x:Key="QtyColHeader">
<Border Style="{StaticResource BlueBorder}">
<TextBlock Text="Quantity " Style="{StaticResource ColHeaderText}" />
< span>Border>
< span>DataTemplate>
<DataTemplate x:Key="QtyCellTemplate">
<TextBlock Foreground="MediumBlue"
Text="{Binding Path=Quantity}" />
< span>DataTemplate>
Followed by the additional column in the ListView itself:
<GridViewColumn
HeaderTemplate="{StaticResource QtyColHeader}"
CellTemplate="{StaticResource QtyCellTemplate}">
< span>GridViewColumn>
With just the raw quantity values showing in the new column, the ListView now looks like this:

For the sake of example, let's say that we want to highlight in red all values that are less than 200. First we create a class that implements IValueConverter. This implementation requires two methods - Convert and ConvertBack - each with a standard signature. Here is the code, which can be placed in a file of its own or - as I have chosen to do - appended to the end of (but not inside!) the Application.xaml.vb file:
Public Class IntegerToBrushConverter
Implements IValueConverter
Public Function Convert(ByVal value As Object, ByVal targetType As Type, _
ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) _
As Object Implements IValueConverter.Convert
' Only allow conversion if the correct TargetType is passed in.
' (This is optional)
If targetType IsNot GetType(Brush) Then
Return Nothing
End If
' If less than 200 in stock, display in Red, otherwise use
' the default of MediumBlue
Dim Result As Integer = Integer.Parse(value.ToString())
Return (If(Result < 200, Brushes.Red, Brushes.MediumBlue))
End Function
Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, _
ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) _
As Object Implements IValueConverter.ConvertBack
' Not used, so throw exception if this method is called.
Throw New NotImplementedException()
End Function
End Class
As you can see from the comments, I have chosen to test that a Brush object is passed in to the method. This isn't mandatory but is often worth including. The second test in the Convert method checks the value of the current field and if it finds the value to be less than 200, Returns a Red Brush, otherwise it Returns a MediumBlue Brush.
Clearly, what is needed next is some mechanism that is watching for those returned values and making use of the particular brush that is returned. This is handled in the markup in the Application.xaml file. If you are wondering why the markup is in Application.xaml and not the Window that contains the ListView, the reason is that we need to set the conversion on the DataTemplate that formats the Quantity column. And that DataTemplate is in Application.xaml.
As things stand, the XAML markup is unable to access the code above directly. So the first requirement is to map the current project into an XML namespace, making it possible to create a direct link between the two. The syntax for this is as follows:
xmlns:local="clr-namespace:WPFListview"
which is placed in the Application.xaml file, just below the default XML namespaces which are placed there automatically. This now gives the ability to refer to the IntegerToBrushConverter in the XAML markup. (You may find that you have to Rebuild the solution to remove the wavy blue error mark after you first enter this. )
Now that the mapping is in place, I can create an instance of the IntegerToBrushConverter class and assign it a key so that it can be referred to in the XAML.
<local:IntegerToBrushConverter x:Key="QtyConverter" />
The final step is to use this instance of the converter inside the DataTemplate for the Quantity column. This markup is in the Application.xaml file:
<DataTemplate x:Key="QtyCellTemplate">
<TextBlock
Text="{Binding Path=Quantity}"
Foreground="{Binding Path=Quantity, Converter={StaticResource QtyConverter}}"/>
< span>DataTemplate>
The only change is to the Foreground property in the markup,which I have changed from the original hard-coded value of MediumBlue to the Binding you can see there. The syntax is reasonably straightforward:
- The Path has to be an Integer type because that is what the IntegerToBrushConverter expects.
- The relevant Path points to the field that the column is being databound to - Quantity.
- The Converter in the Binding refers to that instance of the IntegerToBrushConverter created a few moments ago and given the key of 'QtyConverter'.
The resulting display when the project runs is now:

Just to briefly cover the ConvertBack method, you can see from the commenting that this method isn't of use to us in this scenario. However, IValueConverter requires that it is included, so we simply throw an Exception if this method should be accessed at any point.
This has been a very simple example of using a ValueConverter, but it includes all the key steps. I plan to cover some more complex scenarios in later blogs.