The Best C# Programmer In The World - Ben Perkins Member Login  | Newsletter | RSS Feeds


 
 
 
TheBestCSharpProgrammerInTheWorld.com 
 
The Best C# Programmer In The World - Ben Perkins
Add images dynamically to WPF DataGrid using IValueConverter in C#  
 
Add images dynamically to WPF DataGrid using IValueConverter in C#
 
Please rate:
 
I created a WPF project which included a DataGrid which present a Status. It looked liked this.
 
 
I didn’t really like the representation of the True, False, Null and decided to convert the value to either a Green, Yellow or Red image instead.
 
To do this, I first added a class called BoolToImageConverter which implements the IValueConverter interface, then an Images directory and then images to my project, as shown below.
 
 
                         using System.Windows.Data;
                        public class BoolToImageConverter : IValueConverter
                        {

                        }                       
                         
 
 
The IValueConverter requires the implementation of 2 methods. The Convert() and ConvertBack() methods. These methods have a CultureInfo parameter which is part of the System.Globalization namespace. The ConvertBack() will not be used but is implemented like the below for this example.
 
 
                         using System.Globalization;
                        public object ConvertBack(object value, 
                                                  Type targetType, 
                                                  object parameter, CultureInfo culture)
                        {
                            throw new System.NotImplementedException();
                        }                       
                         
 
The Convert() method is the most important and is shown below.
 
 
                    using System.Data;
                    using System.Windows.Media.Imaging;
        
                    public object Convert(object value, Type targetType, 
                                     object parameter, CultureInfo culture)
                    {
                      if (value is DataRowView)
                      {
                        DataRowView row = value as DataRowView;
                        if (row != null)
                        {
                          if (row.DataView.Table.Columns.Contains("Status"))
                          {
                            Type type = row["Status"].GetType();
                            string status = (string)row["Status"];
                            if (status == "Null")
                            {
                              Uri uri = 
                                new Uri("pack://application:,,,/Images/yellow.jpg");
                              BitmapImage source = new BitmapImage(uri);
                              return source;
                            }
                            if (status == "True")
                            {
                              Uri uri = 
                                new Uri("pack://application:,,,/Images/green.jpg");
                              BitmapImage source = new BitmapImage(uri);
                              return source;
                            }
                            if (status == "False")
                            {
                              Uri uri = 
                                new Uri("pack://application:,,,/Images/red.jpg");
                              BitmapImage source = new BitmapImage(uri);
                              return source;
                            }
                           }
                          }
                         }
                         return null;
                       }
                         
 
The above method will be called from XAML code which will pass a DataRowView as the value. It checks the Status column for the value and converts it to a green, yellow or red image.
 
The following updates needs to be made to the MainWindow.xaml file.
 
Add the below to the Window element.
 
 
                        xmlns:local="clr-namespace:FilterWPF"
                         
 
Then, after the Window element and before the Grid element add the following Windows.Resources element.
 
 
                        <Window.Resources>
                          <local:BoolToImageConverter x:Key="ConvertBoolToImage" />
                          <DataTemplate x:Key="StatusImage" x:Name="mStatusImage">
                            <Image Width="16" Height="16" Margin="3,0" 
                               Source="{Binding 
                                      Converter={StaticResource ConvertBoolToImage}}" />
                          </DataTemplate>
                        </Window.Resources>
                         
 
Notice that the BoolToImageConverter class is identified and the Key value set to CovertBoolToImage. Within the DataTemplate element the Key is set to StatusImage and the source binds to Convertor which links to the BoolToImageConverter class via its Key value.
 
Next we need to override a method within the System.Windows.Controls.DataTemplateSelector class. This method is called SelectTemplate() and is overridden as below.
 
  
                        public override 
                             DataTemplate SelectTemplate(object inItem, 
                                                         DependencyObject inContainer)
                        {
                            DataRowView row = inItem as DataRowView;

                            if (row != null)
                            {
                                if (row.DataView.Table.Columns.Contains("Status"))
                                {
                                    MainWindow w = GetMainWindow(inContainer);
                                    return (DataTemplate)w.FindResource("StatusImage");
                                }
                            }
                            return null;
                        }
                         
 
The above method calls another method existing within the same class I have called DataTemplateSelectorBase. The method is called GetMainWindow and is shown below.
 
  
                        protected MainWindow GetMainWindow(DependencyObject inContainer)
                        {
                            DependencyObject c = inContainer;
                            while (true)
                            {
                                DependencyObject p = VisualTreeHelper.GetParent(c);

                                if (c is MainWindow)
                                {
                                    return c as MainWindow;
                                }
                                else
                                {
                                    c = p;
                                }
                            }
                        }
                         
 
The final step is to create a method within the MainWindow.cs code-behind to insert the column. The code is below and should be called from the Window_Loaded() found in the MainWIndow.cs.
 
  
                        public void SetStatusColumn()
                        {
                            DataGridTemplateColumn statusColumn = 
                                    new DataGridTemplateColumn 
                            { 
                              CanUserReorder = false, Width = 85, CanUserSort = false 
                            }; ;
                            statusColumn.Header = "Status";
                            statusColumn.CellTemplateSelector = 
                                     new DataTemplateSelectorBase();
                            dataGrid1.Columns.Insert(0, statusColumn);
                        }
                         
 
Running the WPF results now in the below window containing images.
 
 
This is good but now I have 2 columns called Status. I added the below code after binding the data to the DataGrid but before calling the SetStatusColumn() method.
 
  
                        dataGrid1.Columns[0].Visibility = 
                                  System.Windows.Visibility.Hidden;
                         
 
The above line of code prevents the first column in the data set from being displayed in the DataGrid. The result is a WPF program which now resembles the below.
 
 
Adding images instead of text make a program simpler to use and understand. Little things like this can really increase the acceptance or sale of a program. Use it well.
 
NOTE: I did initially set the Status value as a bool, however, due to the way I load the data for this example I needed to change it to a string. When the data is loaded from a real data source and a value is a bool, then it will work with a bool, simple change the boxing from string to bool. The fact that I made a bool into a string should NOT be reproduced. This was done only because of the way I load the data into the Datagrid.
 
Download the source
 
 
Feedback / Question
 
Your Name:Your Email:
 
Subject:
 
Feedback/Question:
 
 
 
I had to remove the capability to leave feedback due to this. Will be back soon.
 
 
page.Translate()
 
 
blog.Stats()
 
  Posts: 113
  Comments: 86
  Fundamentals: 16
 
my.Book()

 
me.About()
 
 
 
 
 
blog.Archive()
 
2012 May  (4)
2012 April  (5)
2012 March  (4)
2012 February  (4)
2012 January  (5)
2011 December (2)
2011 November (6)
2011 October (7)
2011 September (7)
2011 August (9)
2011 July (9)
2011 June (8)
2011 May (9)
2011 April (7)
2011 March (9)
2011 February (8)
2011 January (8)
2010 December (7)
2010 November (8)
2010 October (4)
 
site.Visits()
 
free counters
 
tag.Cloud()
 
code.Disclaimer()
 
The sample code on this website is provided to illustrate a concept and should not be used in applications or Web sites without proper professional consultation, as it may not illustrate the safest coding practices. I assume no liability for incidental or consequential damages should the sample code be used for purposes other than as intended.
 
   


The Best C# Programmer In The World - Ben Perkins, © 2010, All Rights ReservedContact Ben