Click here to Skip to main content
Click here to Skip to main content

WPF Introduction: Databinding + Styles + IValueConverter

, 5 Aug 2009
Rate this:
Please Sign up or sign in to vote.
A small introduction about Listview Databinding and Styles with introduction to IValueConverter interface

Introduction

While I was a newbie to WPF, I was finding it difficult to get a grasp of the Databinding concepts and applying styles in particular for a control. I found few articles explaining those concepts for a newbie. This article will give you a basic idea about applying styles to a listview, binding a class object with the listview. Finally, I give an introduction to the IValueConverter interface which is newly introduced in .NET 3.0.

Application Screenshot

1.PNG

The above window has the following features:

  1. A style is provided to listview – alternate rows are highlighted with different colors.
  2. The listview is databound to an object of Employee class.
  3. In the class, we will specify whether an employee is a manager or not as a Boolean value. But it will be displayed as ‘Yes’ or ‘No’ in the gridview. It is performed by means of a converter. The style also utilizes a converter. Both the converters use IValueConverter interface newly introduced in .NET 3.0.

Step by Step Procedure

We will see how we can achieve the above application and features in a step by step manner.

Step #1: Making Application Skeleton Ready

Create a new WPF Application Project.

2.PNG

Change the Window1.xaml as ListViewDataBindingSample.xaml:

3.PNG

Change the StartupUri in App.xaml as ListViewDataBindingSample.xaml:

4.PNG

Step #2: Creating EmployeeData Class to Populate Listview

Create a class called EmployeeData.cs in the ListViewDatabindingSample project.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ListViewDataBinding
{
    public class EmployeeData
    {
        private int _empID;
        public int EmpID
        {
            get { return _empID; }
            set { _empID = value; }
        }

        private string _empName;
        public string EmpName
        {
            get { return _empName; }
            set { _empName = value; }
        }

        private string _designation;
        public string Designation
        {
            get { return _designation; }
            set { _designation = value; }
        }

        private bool _isManager;
        public bool IsManager
        {
            get { return _isManager; }
            set { _isManager = value; }
        }

        private int _age;
        public int Age
        {
            get { return _age; }
            set { _age = value; }
        }

        public EmployeeData(int empID,string empName,string designation,
						bool isManager,int age)
        {
            EmpID = empID;
            EmpName = empName;
            Designation = designation;
            IsManager = isManager;
            Age = age;
        }            
    }
}

Step #3: Adding Listview

We set the viewmode of Listview as Gridview to display Grid like structure for displaying in tabular format. The GridView class and its supporting classes provide the infrastructure to display data items that are specified for a ListView control in a series of columns.

<Window x:Class="ListViewDataBindingSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Databinding Sample" Height="300" Width="615">
    <Grid  Name="gridElements" VerticalAlignment="Stretch" >
            <ListView  Name="lsvElements" FontSize="11" 
		BorderBrush="DarkGray" BorderThickness="1">
                <ListView.View>
                    <GridView AllowsColumnReorder="True">
                        <GridViewColumn DisplayMemberBinding="{Binding Path=EmpID}" 
					Header="EmpID" Width="75"/>
                        <GridViewColumn DisplayMemberBinding="{Binding Path=EmpName}" 
					Header="Name" Width="200"/>
                        <GridViewColumn DisplayMemberBinding="{Binding Path=Designation}" 
					Header="Designation" Width="175" />
                        <GridViewColumn DisplayMemberBinding="{Binding Path=IsManager}" 
					Header="IsManager" Width="75" />
                        <GridViewColumn DisplayMemberBinding="{Binding Path=Age}" 
					Header="Age" Width="75"/>
                    </GridView>
                </ListView.View>
            </ListView>
        </Grid>
</Window>

Since we will bind a class object and the listview columns, we need to specify the class property which is going to be bound with which column. The first column will be bounded with EmpID property of EmployeeData class. In a similar way, define for other columns. Now we have a plain listview and will try to populate it.

Step #4: Populating Listview

Add the following code in the constructor:

List<employeedata> employeeDataList = new List<employeedata>();
EmployeeData e1 = new EmployeeData(3809, "Sathish Kumar", 
		"Application Developer", false, 28);
EmployeeData e2 = new EmployeeData(3810, "Ambalavanar", 
		"Senior Application Developer", false, 28);
EmployeeData e3 = new EmployeeData(2783, "Raghuraman", 
		"Senior Application Developer", false, 26);
EmployeeData e4 = new EmployeeData(2157, "Balasubramaninan", 
		"Project Leader", false, 34);
EmployeeData e5 = new EmployeeData(3151, "Raja Natarajan", 
		"Development Manager", true, 37);
employeeDataList.Add(e1);
employeeDataList.Add(e2);
employeeDataList.Add(e3);
employeeDataList.Add(e4);
employeeDataList.Add(e5);

lsvElements.ItemsSource = employeeDataList;

If you run the application, you can see a plain listview with Employee Details.

5.PNG

Step #5: Using IValueConverter Interface

If you closely watch the above screen shot, we have IsManager columns displaying False or True. Instead we would like to have No or Yes, which will be meaningful. Add a class BooleanValue.cs to the project. Make the class public and add namespace System.Windows.Data.

Inherit the above class from IValueConverter interface. Implement the interface.

6.PNG

As stated in the MSDN:

If you want to associate a value converter with a binding, create a class that implements the IValueConverter interface and then implement the Convert and ConvertBack methods. Converters can change data from one type to another, translate data based on cultural information, or modify other aspects of the presentation.

In our case, we would like to change the Boolean value into a string. If the Boolean value is True, then string returned should be ‘Yes’ and vice versa. We have implemented it in the Convert method. But we are not implementing the ConvertBack method.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;

namespace ListViewDataBindingSample
{
    public class BooleanConverter : IValueConverter
    {

        #region IValueConverter Members

        public object Convert(object value, Type targetType, 
		object parameter, System.Globalization.CultureInfo culture)
        {
            string returnValue = string.Empty;
            if ((bool)value == true)
            {
                returnValue = "Yes";
                return (string)returnValue;
            }
            else
            {
                returnValue = "No";
                return (string)returnValue;
            }
        }

        public object ConvertBack(object value, Type targetType, 
		object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}

The bold faced changes have been make in the XAML file to make the converter work.

<Window x:Class="ListViewDataBindingSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ListViewDataBindingSample"
    Title="Databinding Sample" Height="300" Width="615">
    <Window.Resources>
        <local:BooleanConverter x:Key="formatter"/>
      </Window.Resources> 
    <Grid  Name="gridElements" VerticalAlignment="Stretch" >
            <ListView  Name="lsvElements" FontSize="11" 
		BorderBrush="DarkGray" BorderThickness="1">
                <ListView.View>
                    <GridView AllowsColumnReorder="True">
                        <GridViewColumn DisplayMemberBinding="{Binding Path=EmpID}" 
				Header="EmpID" Width="75"/>
                        <GridViewColumn DisplayMemberBinding="{Binding Path=EmpName}" 
				Header="Name" Width="200"/>
                        <GridViewColumn DisplayMemberBinding="{Binding Path=Designation}" 
				Header="Designation" Width="175" />
                        <GridViewColumn DisplayMemberBinding="{Binding Path=IsManager, 
				Converter={StaticResource formatter}}" 
				Header="IsManager" Width="75" /> 
                        <GridViewColumn DisplayMemberBinding="{Binding Path=Age}" 
				Header="Age" Width="75"/>
                    </GridView>
                </ListView.View>
            </ListView>
        </Grid>
</Window>

So, whenever the listview encounters True, it will replace it with ‘Yes’ and False with ‘Nostring. This is one of the powerful conversion utilities in WPF.

If you run the application, it will look like this:

7.PNG

Step #6: Styling Listview

WPF provides an excellent class called ResourceDictionary. It can contain resources used by components and other elements of a WPF application. We will define the component style in one place, wherever we use that component – that will automatically follow that style. For example, define a style for a button with features like - round rectangle, glossy effects. In the entire application wherever you use a button, it will follow the UI design specified in the styles.

Now we will try to have alternate rows having different colors. Let the first row’s background be white and the next row’s background be light sky blue.

As we discussed, we would like to have alternate colors (white and light sky blue), we will use a Converter class for doing it. Add a class named as BackgroundConverter.cs to the project. Implement the IValueConverter interface as discussed previously. In this converter, we will change the color of the background depending upon the index of the listview. The code for BackgroundConverter.cs is listed below:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Controls;

namespace ListViewDataBindingSample
{
    public sealed class BackgroundConverter : IValueConverter
    {
        SolidColorBrush lightBlueBrush = 
		new SolidColorBrush(Color.FromArgb(255, 240, 245, 255));

        public object Convert(object value, Type targetType, 
		object parameter, System.Globalization.CultureInfo culture)
        {
            ListViewItem item = (ListViewItem)value;
            ListView listView = 
		ItemsControl.ItemsControlFromItemContainer(item) as ListView;
            // Get the index of a ListViewItem
            int index = listView.ItemContainerGenerator.IndexFromContainer(item);

            if (index % 2 == 0)
            {
                return lightBlueBrush;
            }
            else
            {
                return Brushes.White;
            }
        }

        public object ConvertBack(object value, Type targetType, 
		object parameter, System.Globalization.CultureInfo culture)
        {
            ListViewItem item = (ListViewItem)value;
            ListView listView = 
		ItemsControl.ItemsControlFromItemContainer(item) as ListView;
            // Get the index of a ListViewItem
            int index = listView.ItemContainerGenerator.IndexFromContainer(item);

            if (index % 2 == 0)
            {
                return lightBlueBrush;
            }
            else
            {
                return Brushes.White;
            }
        }
    }
}

Add a new Resource Dictionary file in the project as ListViewStyle.xaml. (Right click on project > click ‘Add’ > click ‘Resource Dictionary…’ menu). Add the below code in the resource dictionary:

<ResourceDictionary
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
 xmlns:appStyles="clr-namespace:ListViewDataBindingSample">

    <!-- ListViewItem Alternate colour template-->
    <appStyles:BackgroundConverter x:Key="AlternateBackgroundConverter"/>


    <Style x:Key="ListViewAlternateItemStyle" TargetType="{x:Type ListViewItem}">
        <Setter Property="SnapsToDevicePixels" Value="true"/>
        <Setter Property="OverridesDefaultStyle" Value="true"/>
        <Setter Property="Background">
            <Setter.Value>
                <Binding RelativeSource="{RelativeSource Self}" 
                 Converter="{StaticResource AlternateBackgroundConverter}"/>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListBoxItem">
                    <Border Name="Border" Margin="-3,0,1,0" Padding="0,3,0,3"
                  SnapsToDevicePixels="True" Background="{TemplateBinding Background}">
                        <StackPanel Orientation="Horizontal">
                            <GridViewRowPresenter VerticalAlignment="Center"/>
                        </StackPanel>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="true">
                            <Setter TargetName="Border" Property="Background">
                                <Setter.Value>
                                    <LinearGradientBrush EndPoint="0.5,1" 
					StartPoint="0.5,0">
                                        <GradientStop Color="#FFD4DFFE" Offset="0"/>
                                        <GradientStop Color="#FFE0E4EF" Offset="1"/>
                                    </LinearGradientBrush>
                                </Setter.Value>
                            </Setter>
                            <Setter TargetName="Border" 
				Property="CornerRadius" Value="2"/>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="#888"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

WPF provides us the flexibility to change the structure and appearance of a control by modifying the controltemplate of that control. In the above case, we are changing the basic template property of listview along with background property. Note that we are using the BackgroundConverter class.

  1. Background – The background property uses the AlternateBackgroundConverter converter which toggles between white and light sky blue colors.
  2. Template - For ListBoxItem we are binding the background property set above. Also when a row is selected, we darken the color of the row to differentiate from other rows.

If we run the application, we won’t see any changes in the list view. To make the changes to be updated in the application, we have to add the below line in the app.xaml. We use merged resource dictionary which provides a way to define the resource portion of a WPF application outside of the compiled XAML application.

<Application x:Class="ListViewDataBindingSample.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="ListViewDataBindingSample.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="ListViewStyle.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Also, the listview in the ListViewBindingSample.xaml should use the above style. Now the complete XAML code for the application will become like the one shown below:

<Window x:Class="ListViewDataBindingSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ListViewDataBindingSample"
    Title="Databinding Sample" Height="300" Width="615">
    <Window.Resources>
        <local:BooleanConverter x:Key="formatter"/>
    </Window.Resources>
    <Grid  Name="gridElements" VerticalAlignment="Stretch" >
            <ListView  Name="lsvElements" FontSize="11" 
			BorderBrush="DarkGray" BorderThickness="1" 
                    ItemContainerStyle="{DynamicResource ListViewAlternateItemStyle}">
                <ListView.View >
                    <GridView AllowsColumnReorder="True">
                        <GridViewColumn DisplayMemberBinding="{Binding Path=EmpID}" 
				Header="EmpID" Width="75"/>
                        <GridViewColumn DisplayMemberBinding="{Binding Path=EmpName}" 
				Header="Name" Width="200"/>
                        <GridViewColumn DisplayMemberBinding=
				"{Binding Path=Designation}" 
				Header="Designation" Width="175" />
                        <GridViewColumn DisplayMemberBinding="{Binding Path=IsManager, 
				Converter={StaticResource formatter}}" 
				Header="IsManager" Width="75" />
                        <GridViewColumn DisplayMemberBinding="{Binding Path=Age}" 
				Header="Age" Width="75"/>
                    </GridView>
                </ListView.View>
            </ListView>
        </Grid>
</Window>

The final application screen will look like this:

8.PNG

Points of Interest

  1. It is possible to make the headers with different colors, also sortable. 
  2. It is also possible to display a row color, depending upon a data item.

History

  • Version 1.0 - Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Sathishkumar_P
Software Developer (Senior)
India India
Working in a software development company specializing financial products as Senior Developer. Interested in WPF, WCF, C# and C.

Comments and Discussions

 
GeneralUpdating employeeDataList from a thread Pinmembersuranasaurabh2-Sep-09 5:18 
GeneralRe: Updating employeeDataList from a thread PinmemberSathishkumar_P3-Sep-09 0:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 6 Aug 2009
Article Copyright 2009 by Sathishkumar_P
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid