Click here to Skip to main content
11,648,094 members (65,787 online)
Click here to Skip to main content

WPF Introduction: Databinding + Styles + IValueConverter

, 5 Aug 2009 CPOL 44.7K 765 21
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 IValueConverterinterface 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 Employeeclass.
  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 IValueConverterinterface 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 StartupUriin App.xaml as ListViewDataBindingSample.xaml:

4.PNG

Step #2: Creating EmployeeData Class to Populate Listview

Create a class called EmployeeData.cs in the ListViewDatabindingSampleproject.

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 Listviewas Gridviewto display Grid like structure for displaying in tabular format. The GridViewclass and its supporting classes provide the infrastructure to display data items that are specified for a ListViewcontrol 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 listviewcolumns, we need to specify the class property which is going to be bound with which column. The first column will be bounded with EmpIDproperty of EmployeeDataclass. In a similar way, define for other columns. Now we have a plain listviewand 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 listviewwith EmployeeDetails.

5.PNG

Step #5: Using IValueConverter Interface

If you closely watch the above screen shot, we have IsManagercolumns 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 publicand add namespace System.Windows.Data.

Inherit the above class from IValueConverterinterface. 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 IValueConverterinterface and then implement the Convertand ConvertBackmethods. 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 Booleanvalue into a string. If the Booleanvalue is True, then stringreturned should be ‘Yes’ and vice versa. We have implemented it in the Convertmethod. But we are not implementing the ConvertBackmethod.

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 listviewencounters True, it will replace it with ‘Yes’ and Falsewith ‘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 Converterclass for doing it. Add a class named as BackgroundConverter.cs to the project. Implement the IValueConverterinterface 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 listviewalong with background property. Note that we are using the BackgroundConverterclass.

  1. Background– The backgroundproperty uses the AlternateBackgroundConverterconverter which toggles between white and light sky blue colors.
  2. Template- For ListBoxItemwe are binding the backgroundproperty 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 listviewin 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)

Share

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.

You may also be interested in...

Comments and Discussions

 
GeneralUpdating employeeDataList from a thread Pin
suranasaurabh2-Sep-09 5:18
membersuranasaurabh2-Sep-09 5:18 
GeneralRe: Updating employeeDataList from a thread Pin
Sathishkumar_P3-Sep-09 0:10
memberSathishkumar_P3-Sep-09 0:10 
GeneralCouldn't resist Pin
Bob Bedell10-Aug-09 15:26
memberBob Bedell10-Aug-09 15:26 
GeneralRe: Couldn't resist Pin
Sathishkumar_P10-Aug-09 19:03
memberSathishkumar_P10-Aug-09 19:03 
GeneralRe: Couldn't resist Pin
Shorgov16-Aug-09 22:53
memberShorgov16-Aug-09 22:53 
GeneralRe: Couldn't resist Pin
Sathishkumar_P16-Aug-09 23:01
memberSathishkumar_P16-Aug-09 23:01 

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 | Terms of Use | Mobile
Web01 | 2.8.150804.4 | Last Updated 6 Aug 2009
Article Copyright 2009 by Sathishkumar_P
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid