none
how to add image dynamically to datagrid columns

    Question

  • Hello,

     

    I have datagrid in which i have to display image conditionally , suppose in my grid i have one column of percentage then i have to add green signal image for percentage above 80 and yellow signal for below 50 indicating pass and red signal for failed students how is this possible?

    i get data from sharepoint service.

    i do not have fixed columns , i bind columns dynamically in code behind plz help me urgently.

    thanks  

    Tuesday, July 27, 2010 10:03 AM

Answers

  • can you give me some sample for Converter class with this type of condition, my images are stored in project only.

    See this thread:

    http://betaforums.silverlight.net/forums/p/187291/429215.aspx


    Wednesday, July 28, 2010 11:19 AM
  • The value you'll be passing in is the grade that needs to have an image associated with it.

    Public Class ImageConverter
        Implements IValueConverter
    
        Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object _
            Implements System.Windows.Data.IValueConverter.Convert
            Select Case CInt(value)
                Case Is > 80
                    Return New BitmapImage(New Uri("../Images/Green.png", UriKind.Relative))
                Case Is > 50
                    Return New BitmapImage(New Uri("../Images/Yellow.png", UriKind.Relative))
                Case Else
                    Return New BitmapImage(New Uri("../Images/Red.png", UriKind.Relative))
            End Select
        End Function
    
        Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
            Throw New NotImplementedException
        End Function
    End Class


    Here's how I set up my template column.  It doesn't matter if you do it like this or from XAML like sladapter suggested.

            Dim Grades As New List(Of Integer)(New Integer() {90, 50, 70, 95, 85, 30})
    
            Dim sp As New StackPanel
            sp.Orientation = Orientation.Vertical
            LayoutRoot.Children.Add(sp)
    
            Dim dg As New DataGrid
            dg.ItemsSource = Grades
            dg.AutoGenerateColumns = False
            sp.Children.Add(dg)
    
            Dim dt = (<DataTemplate
                          xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                          xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
                          xmlns:my='clr-namespace:TestRC2;assembly=TestRC2'>
                          <Grid>
                              <Grid.Resources>
                                  <my:ImageConverter x:Key='ImageConverter'/>
                              </Grid.Resources>
                              <Image Source='{Binding Converter={StaticResource ImageConverter}}'/>
                          </Grid>
                      </DataTemplate>).ToString()
    
            Dim tc As New DataGridTemplateColumn
            tc.Header = "Image Column"
            tc.CellTemplate = XamlReader.Load(dt)
            dg.Columns.Add(tc)

    Put a break point in the Select Case statement and you'll see the grade being passed in as the value.

    Thursday, July 29, 2010 10:25 AM
  • so this is the code ok but i have not understood what is parameter, targettype,value

    what is YourDataObject in my case , is it string or something else?

    The value parameter in the Converter is the data you passed in the Binding. Say your data object is something like this:

    public class YourData

    {

        public int Percentage {get;set;}

        public string Name {get; set;}

        ...

    }

    You set the binding like this by specifying a Path:

    <Image Source="{Binding Percentage, Converter="{StaticResource YourUrlConverter}}" .../>

    Then the value object should be the Percentage, the code should be like this:

            int p = value as int;

            if(p > 80)

                 return GreenImageURL;

            else if(p<50)

                 return YellowImageURL;

           else

               ...

    If you set the Binding without providing a path, then the Value object would be the whole DataContext which is YourData object:

    <Image Source="{Binding Converter="{StaticResource YourUrlConverter}}" ../>

    The code should be like this:

      YoudData data= value as YourData;

            if(data.Percentage > 80)

                 return GreenImageURL;

            else if(data.Percentage <50)

                 return YellowImageURL;

           else

               ...


    "Parameter" can be useful. You can specify ConverterParameter in the binding, it gives you extra control on how to do the conversion. Using it to provide Format string is a good example.



    Thursday, July 29, 2010 11:48 AM
  • sladapter is correct that I was binding to the DataContext of the DataGrid which in my previous example was simply a list of Integer.

    Here's a more complete example using a Student class.  It implements INotifyProperty changes which the ObservableCollection can take advantage of so when you change the Student's score in the numeric column the image changes to reflect the new score.

    The ImageConverter is the same one I used in my previous post.

    Public Class Student
        Implements INotifyPropertyChanged
    
        Public Sub New(ByVal name As String, ByVal score As Integer)
            _name = name
            _score = score
        End Sub
    
        Private Property _name As String
        Public Property name As String
            Get
                Return _name
            End Get
            Set(ByVal value As String)
                _name = value
                RaisePropertyChanged("name")
            End Set
        End Property
    
        Private Property _score As Integer
        Public Property score As Integer
            Get
                Return _score
            End Get
            Set(ByVal value As Integer)
                _score = value
                RaisePropertyChanged("score")
            End Set
        End Property
    
        Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) _
            Implements INotifyPropertyChanged.PropertyChanged
    
        Sub RaisePropertyChanged(ByVal propertyName As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
        End Sub
    End Class

            Dim Students As New ObservableCollection(Of Student) From {
                New Student("Joe", 90),
                New Student("Mary", 50),
                New Student("Billy", 70),
                New Student("Shelly", 95),
                New Student("Johnny", 85),
                New Student("Tim", 30)
            }
    
            Dim sp As New StackPanel
            sp.Orientation = Orientation.Vertical
            LayoutRoot.Children.Add(sp)
    
            Dim dg As New DataGrid
            dg.ItemsSource = Students
            dg.AutoGenerateColumns = False
            sp.Children.Add(dg)
    
            Dim namesColumn As New DataGridTextColumn
            namesColumn.Header = "Text Column"
            namesColumn.Binding = New Data.Binding With
                                  {
                                      .Path = New PropertyPath("name")
                                  }
            dg.Columns.Add(namesColumn)
    
            Dim scoresImageTemplate = (<DataTemplate
                                           xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                                           xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
                                           xmlns:my='clr-namespace:TestRC2;assembly=TestRC2'>
                                           <Grid Width='50' Height='50'>
                                               <Grid.Resources>
                                                   <my:ImageConverter x:Key='ImageConverter'/>
                                               </Grid.Resources>
                                               <Image Source='{Binding score, Converter={StaticResource ImageConverter}}'/>
                                           </Grid>
                                       </DataTemplate>).ToString()
    
            Dim scoresImageTemplateColumn As New DataGridTemplateColumn
            scoresImageTemplateColumn.Header = "Image Column"
            scoresImageTemplateColumn.CellTemplate = XamlReader.Load(scoresImageTemplate)
            dg.Columns.Add(scoresImageTemplateColumn)
    
            Dim scoresNumericColumn As New DataGridTextColumn
            scoresNumericColumn.Header = "Scores Text Column"
            scoresNumericColumn.Binding = New Data.Binding With
                                   {
                                       .Path = New PropertyPath("score"),
                                       .Mode = Data.BindingMode.TwoWay
                                   }
            dg.Columns.Add(scoresNumericColumn)




    Thursday, July 29, 2010 4:33 PM
  • Ah, you're getting a message that ImageConverter couldn't be found because 'my' is an unknown namespace.  Add the assembly information to your declaration and that should go away (Take a look at my previous code for an example).

    Tuesday, August 03, 2010 10:10 AM

All replies

  • You can use an image converter to achieve this.  Here's an example of setting up a template column to use an image converter from code behind.

            Dim tc As New DataGridTemplateColumn
            tc.Header = "Your Header"
    
            Dim sb As New StringBuilder
            sb.Append("<DataTemplate ")
            sb.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ")
            sb.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' ")
            sb.Append("xmlns:local = 'clr-namespace:YourNamespace;assembly=YourAssembly'>")
            sb.Append("<Grid>")
            sb.Append("<Grid.Resources>")
            sb.Append("local:ImageConverter x:Key='ImageConverter' />")
            sb.Append("</Grid.Resources>")
            sb.Append("<TextBlock ")
            sb.Append("Text = '{Binding YourField, ")
            sb.Append("Converter={StaticResource ImageConverter}}' ")
            sb.Append("</Grid>")
            sb.Append("</DataTemplate>")
    
            tc.CellTemplate = XamlReader.Load(sb.ToString())
            YourDataGrid.Columns.Add(tc)


    Tuesday, July 27, 2010 10:29 AM
  • i do not have fixed columns , i bind columns dynamically in code behind plz help me urgently.

    Define a DataGridCellTemplate in XAML and put a Image control in the Cell. Set the Binding on the Source property:

    <DataTemplate x:Key="ImageColTemplate">

       <Image Source="{Binding Converter="{StaticResource ImageConverter}" />

    </DataTemplate>

    Write your ImageConverter so it returns correct image URL based on the Data on that row.

    In your code, create a DataTemplateColumn,

    DataGridTemplateColumn col = new DataGridTemplateColumn();
    col.CellTemplate = this.Resources["ImageColTemplate"] as DataTemplate;

    theDataGrid.Columns.Add(col);

    Tuesday, July 27, 2010 10:42 AM
  • this is good idea i at least found some solution for my problem Smile

    where should i write <DataTemplate> part in XAML , i am little bit new to silverlight so i do not know the exact position

    can you give me some sample for Converter class with this type of condition, my images are stored in project only.

    Thanks a lot

     

     

    Wednesday, July 28, 2010 8:19 AM
  • thanks for reply . it is good idea 

    Wednesday, July 28, 2010 8:23 AM
  • where should i write <DataTemplate> part in XAML

    If you want to define it in XAML, you can put it in your UserControl's Resources area:

    <UserControl ...

    >

    <UserControl.Resources>

    <DataTemplate x:Key="yourKey" ... />

    </UserControl.Resources>

    <Grid x:Name="LayoutRoot">

               ....

    </Grid>

    </UserControl>


    Or under your DataGrid.Resources:

    <dg:DataGrid x:Name="DG" ...>

    <dg:DataGrid.Resources>

      <DataTemplate x:Key="yourKey" ... />

    </dg:DataGrid.Resources>

    ...

    </dg:DataGrid>


    Depending on where you put it, in code, you need to refer it in code like this:

    DataTemplate dt = this.Resources["YourKey"] as DataTemplate;  //If you put it under UserControl.Resources

    or

    DataTemplate dt = DG.Resources["YourKey"] as DataTemplate; //If you put it under DataGrid.Resources





    Wednesday, July 28, 2010 11:01 AM
  • can you give me some sample for Converter class with this type of condition, my images are stored in project only.

    See this thread:

    http://betaforums.silverlight.net/forums/p/187291/429215.aspx


    Wednesday, July 28, 2010 11:19 AM
  • public class UrlConverter : IValueConverter
     {

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)      
        {          
            string format = parameter as string;

            YourDataObject  data = value;

            string queryParm = "id=" + data.ID + "&status=" + data.Status ...; // Build your query string here use the DataObject passed in as Value
            if (!string.IsNullOrEmpty(format))             
                return string.Format(culture, format, queryParm);    
            else                 
                return value.ToString();
        }         

     

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
       {
          return null;
        }
    }

    so this is the code ok but i have not understood what is parameter, targettype,value

    what is YourDataObject in my case , is it string or something else?

    and above how should i give URL condition in this code? so as to return correct url of my image.

    Thursday, July 29, 2010 5:33 AM
  • The value you'll be passing in is the grade that needs to have an image associated with it.

    Public Class ImageConverter
        Implements IValueConverter
    
        Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object _
            Implements System.Windows.Data.IValueConverter.Convert
            Select Case CInt(value)
                Case Is > 80
                    Return New BitmapImage(New Uri("../Images/Green.png", UriKind.Relative))
                Case Is > 50
                    Return New BitmapImage(New Uri("../Images/Yellow.png", UriKind.Relative))
                Case Else
                    Return New BitmapImage(New Uri("../Images/Red.png", UriKind.Relative))
            End Select
        End Function
    
        Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
            Throw New NotImplementedException
        End Function
    End Class


    Here's how I set up my template column.  It doesn't matter if you do it like this or from XAML like sladapter suggested.

            Dim Grades As New List(Of Integer)(New Integer() {90, 50, 70, 95, 85, 30})
    
            Dim sp As New StackPanel
            sp.Orientation = Orientation.Vertical
            LayoutRoot.Children.Add(sp)
    
            Dim dg As New DataGrid
            dg.ItemsSource = Grades
            dg.AutoGenerateColumns = False
            sp.Children.Add(dg)
    
            Dim dt = (<DataTemplate
                          xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                          xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
                          xmlns:my='clr-namespace:TestRC2;assembly=TestRC2'>
                          <Grid>
                              <Grid.Resources>
                                  <my:ImageConverter x:Key='ImageConverter'/>
                              </Grid.Resources>
                              <Image Source='{Binding Converter={StaticResource ImageConverter}}'/>
                          </Grid>
                      </DataTemplate>).ToString()
    
            Dim tc As New DataGridTemplateColumn
            tc.Header = "Image Column"
            tc.CellTemplate = XamlReader.Load(dt)
            dg.Columns.Add(tc)

    Put a break point in the Select Case statement and you'll see the grade being passed in as the value.

    Thursday, July 29, 2010 10:25 AM
  • so this is the code ok but i have not understood what is parameter, targettype,value

    what is YourDataObject in my case , is it string or something else?

    The value parameter in the Converter is the data you passed in the Binding. Say your data object is something like this:

    public class YourData

    {

        public int Percentage {get;set;}

        public string Name {get; set;}

        ...

    }

    You set the binding like this by specifying a Path:

    <Image Source="{Binding Percentage, Converter="{StaticResource YourUrlConverter}}" .../>

    Then the value object should be the Percentage, the code should be like this:

            int p = value as int;

            if(p > 80)

                 return GreenImageURL;

            else if(p<50)

                 return YellowImageURL;

           else

               ...

    If you set the Binding without providing a path, then the Value object would be the whole DataContext which is YourData object:

    <Image Source="{Binding Converter="{StaticResource YourUrlConverter}}" ../>

    The code should be like this:

      YoudData data= value as YourData;

            if(data.Percentage > 80)

                 return GreenImageURL;

            else if(data.Percentage <50)

                 return YellowImageURL;

           else

               ...


    "Parameter" can be useful. You can specify ConverterParameter in the binding, it gives you extra control on how to do the conversion. Using it to provide Format string is a good example.



    Thursday, July 29, 2010 11:48 AM
  • sladapter is correct that I was binding to the DataContext of the DataGrid which in my previous example was simply a list of Integer.

    Here's a more complete example using a Student class.  It implements INotifyProperty changes which the ObservableCollection can take advantage of so when you change the Student's score in the numeric column the image changes to reflect the new score.

    The ImageConverter is the same one I used in my previous post.

    Public Class Student
        Implements INotifyPropertyChanged
    
        Public Sub New(ByVal name As String, ByVal score As Integer)
            _name = name
            _score = score
        End Sub
    
        Private Property _name As String
        Public Property name As String
            Get
                Return _name
            End Get
            Set(ByVal value As String)
                _name = value
                RaisePropertyChanged("name")
            End Set
        End Property
    
        Private Property _score As Integer
        Public Property score As Integer
            Get
                Return _score
            End Get
            Set(ByVal value As Integer)
                _score = value
                RaisePropertyChanged("score")
            End Set
        End Property
    
        Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) _
            Implements INotifyPropertyChanged.PropertyChanged
    
        Sub RaisePropertyChanged(ByVal propertyName As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
        End Sub
    End Class

            Dim Students As New ObservableCollection(Of Student) From {
                New Student("Joe", 90),
                New Student("Mary", 50),
                New Student("Billy", 70),
                New Student("Shelly", 95),
                New Student("Johnny", 85),
                New Student("Tim", 30)
            }
    
            Dim sp As New StackPanel
            sp.Orientation = Orientation.Vertical
            LayoutRoot.Children.Add(sp)
    
            Dim dg As New DataGrid
            dg.ItemsSource = Students
            dg.AutoGenerateColumns = False
            sp.Children.Add(dg)
    
            Dim namesColumn As New DataGridTextColumn
            namesColumn.Header = "Text Column"
            namesColumn.Binding = New Data.Binding With
                                  {
                                      .Path = New PropertyPath("name")
                                  }
            dg.Columns.Add(namesColumn)
    
            Dim scoresImageTemplate = (<DataTemplate
                                           xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                                           xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
                                           xmlns:my='clr-namespace:TestRC2;assembly=TestRC2'>
                                           <Grid Width='50' Height='50'>
                                               <Grid.Resources>
                                                   <my:ImageConverter x:Key='ImageConverter'/>
                                               </Grid.Resources>
                                               <Image Source='{Binding score, Converter={StaticResource ImageConverter}}'/>
                                           </Grid>
                                       </DataTemplate>).ToString()
    
            Dim scoresImageTemplateColumn As New DataGridTemplateColumn
            scoresImageTemplateColumn.Header = "Image Column"
            scoresImageTemplateColumn.CellTemplate = XamlReader.Load(scoresImageTemplate)
            dg.Columns.Add(scoresImageTemplateColumn)
    
            Dim scoresNumericColumn As New DataGridTextColumn
            scoresNumericColumn.Header = "Scores Text Column"
            scoresNumericColumn.Binding = New Data.Binding With
                                   {
                                       .Path = New PropertyPath("score"),
                                       .Mode = Data.BindingMode.TwoWay
                                   }
            dg.Columns.Add(scoresNumericColumn)




    Thursday, July 29, 2010 4:33 PM
  • Hello Matt.P,

     

    I have used the code as you gave but it gives me error called unknown  namespace though i have provided my namespace name. everything in code i have coded as per my project.   

    Monday, August 02, 2010 6:40 AM
  • Where are you getting the namespace error?  In the datatemplate for the image column?

    Please post the problem section of your code so I can take a look at it.

    Monday, August 02, 2010 10:57 AM
  • myTemplateColumn.CellTemplate
     = (DataTemplate)XamlReader.Load(
    "<DataTemplate  xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' 
    xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'  
    xmlns:my='clr-namespace:DataSetInDataGrid.Silverlight'>" +
                                                "<Grid Width='50' Height='50'>" +
                                               "<Grid.Resources>" +
                                                   "<my:UrlConvert x:Key='ImageConverter'/>" +
                                               "</Grid.Resources>" +
                                               "<Image Source='{Binding score, Converter={StaticResource ImageConverter}}'/>" +
                                           "</Grid>" + " </DataTemplate>"); 

     

    I have underlined the line where i get the error , and this is what my code. can you please tell me what is failer ?

    Tuesday, August 03, 2010 5:16 AM
  • Ah, you're getting a message that ImageConverter couldn't be found because 'my' is an unknown namespace.  Add the assembly information to your declaration and that should go away (Take a look at my previous code for an example).

    Tuesday, August 03, 2010 10:10 AM
  • Hi Matt.P and Sladpter,

    thanks a lot for your great help, it is working like a magic.

    thanks at ton 

    Wednesday, August 04, 2010 5:43 AM