I've been learning a good deal recently about WPF. Granted, I've not yet moved into the VS2008 world (I think that'll happen this weekend) so some of this code might not work properly under it. Nevertheless, I was working this week on a WPF application requiring the use of logical choices during DataBinding. I hadn't done anything conditional during my DataBinding, and finding a good example on just how to do it led me in a lot of different directions.
<rant>
That's the thing that's been bugging me about WPF, that there's so many alpha, beta, omega, RC, and other sorts of bits out there, that a lot of times the examples are moot by the time I find them. But that's another blog post...
</rant>
Point is, I wanted to demonstrate conditional logic during databinding in as simple a method as possible. As you'll find throughout the samples, one of the main tools you have to do this sort of thing is the System.Windows.Data.IValueConverter interface. In the following example I'll show you how to use this interface (or rather, your own class implementing the interface) to achieve logical decision-making during DataBinding in your WPF applications.
As is the case in most WPF DataBinding scenarios, I'll first make a class that will serve as the entity to be displayed in a list control. The Person class, the code for which is displayed below, will be used as our entity. As we add Person instances to the list box, we'll choose to color each name red or blue. Red names will indicate female persons, whereas blue names will indicate male persons. It's remedial, true, and maybe even a little politically incorrect for those more sensitive audience members, but we like simple. Simple is good when you're learning. Moving on, here's our Person class definition.
30 public class Person
31 {
32 private string _name;
33 private Gender _gender;
34
35 public Person(string name, Gender gender)
36 {
37 _name = name;
38 _gender = gender;
39 }
40
41 public Gender Gender
42 {
43 get { return _gender; }
44 set { _gender = value; }
45 }
46
47 public string Name
48 {
49 get { return _name; }
50 set { _name = value; }
51 }
52 }
53
54 public enum Gender
55 {
56 Male,
57 Female
58 }
Next will be the creation of a class that the XAML code can use during run-time. This class will expose an instance of a List<Person> to which the list box control will be bound.
8 public class PersonDataSource
9 {
10 public PersonDataSource()
11 {
12 _people = new List<Person>();
13 _people.Add(new Person("John Dilworth", Gender.Male));
14 _people.Add(new Person("Anna Humphries", Gender.Female));
15 _people.Add(new Person("Brady Gaster", Gender.Male));
16 _people.Add(new Person("Sam Kinison", Gender.Male));
17 _people.Add(new Person("Julie Knowles", Gender.Female));
18 }
19
20 private List<Person> _people;
21
22 public List<Person> People
23 {
24 get { return _people; }
25 }
26 }
Since we're going to make a decision during the DataBinding we'll need to come up with how we're going to choose the red text or the blue text. To do this, we'll finally get around to creating our own custom converter. The Convert method implementation is what you'll want to pay attention to below.
61 public class PersonColorConverter : System.Windows.Data.IValueConverter
62 {
63 #region IValueConverter Members
64
65 public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
66 {
67 Gender gender = (Gender)value;
68 if(gender == Gender.Male) return System.Windows.Media.Brushes.Blue;
69 if(gender == Gender.Female) return System.Windows.Media.Brushes.Red;
70 return System.Windows.Media.Brushes.Black;
71 }
72
73 public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
74 {
75 throw new Exception("The method or operation is not implemented.");
76 }
77
78 #endregion
79 }
Next, the XAML. Note especially lines 5 and 10 below. Line 5 will point the XAML at an actual CLR namespace in which a "class to be used by the XAML" lives. Line 10 declares an instance of a particular class from said namespace (an instance of the PersonDataSource class) the XAML list box will use as a data source.
1 <Window x:Class="WpfExamples.DataBindingLogic.Window1"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 Title="WpfExamples.DataBindingLogic" Height="300" Width="300"
5 xmlns:local="clr-namespace:WpfExamples.DataBindingLogic"
6 >
7
8 <Window.Resources>
9
10 <local:PersonDataSource x:Key="dataSource"/>
Next, we'll declare an instance of the custom converter class in our XAML file that will be used by the list box during data binding.
11 <local:PersonColorConverter x:Key="converter"/>
Finally, we'll provide a DataTemplate that will instruct each ListBoxItem on how it should display itself. You'll also see the code for the list box below, inclusive with typical DataBinding syntax.
13 <DataTemplate DataType="{x:Type local:Person}">
14 <ListBoxItem Content="{Binding Path=Name}"
Foreground="{Binding Path=Gender, Converter={StaticResource converter}}"/>
15 </DataTemplate>
16
17 </Window.Resources>
18
19 <Grid>
20 <ListBox Width="200" Height="300"
ItemsSource="{Binding Source={StaticResource dataSource}, Path=People}"/>
21 </Grid>
22
23 </Window>
When run, you'll see the result - a simply-styled list box, one glance at which and you know what to expect.
Happy coding!