Sam
Sam

Reputation: 81

Apply Datatemplate for Datagrid autogenerated columns - Dynamic binding of Column Name

I used the Datatemplate for Datagrid columns which is autogenerated set to true, I would like to bind the column Name in Datatemplate dynamically, so that I can use one Datatemplate for all columns, is it Possible??

I have tried with DataGridTemplateColumn and DataTemplate, but it looks like DataGridTemplateColumn I have to create for every Column, so proceed with DataTemplate.

Purpose of using DataTemplate is, based on the column value, it shows the image.

XAML:

<Image Name="theImage" Width="40" Height="30" Source="../Resources/Help.png"/>
   <DataTemplate.Triggers>
    <DataTrigger Binding="{Binding Path=Col1}" Value="0,00">
       <Setter TargetName="theImage" Property="Source" Value="../Resources/pmIcons/minus-256.png"/>
    <DataTrigger Binding="{Binding Path=Col1}" Value="1,00">
        <Setter TargetName="theImage" Property="Source" Value="../Resources/pmIcons/greenRoundTick.png"/>
    </DataTrigger>
     <DataTrigger Binding="{Binding Path=Col1}" Value="2,00">
         <Setter TargetName="theImage" Property="Source" Value="../Resources/pmIcons/redCross.png"/>
     </DataTrigger>     
   </DataTemplate.Triggers>
 </DataTemplate>


<DataTemplate>
<Image Name="theImage" Width="40" Height="30" Source="../Resources/Help.png"/>
   <DataTemplate.Triggers>
    <DataTrigger Binding="{Binding Path=Col2}" Value="0,00">
       <Setter TargetName="theImage" Property="Source" Value="../Resources/pmIcons/minus-256.png"/>
    <DataTrigger Binding="{Binding Path=Col2}" Value="1,00">
        <Setter TargetName="theImage" Property="Source" Value="../Resources/pmIcons/greenRoundTick.png"/>
    </DataTrigger>
     <DataTrigger Binding="{Binding Path=Col2}" Value="2,00">
         <Setter TargetName="theImage" Property="Source" Value="../Resources/pmIcons/redCross.png"/>
     </DataTrigger>   
   </DataTemplate.Triggers>
 </DataTemplate>

Pm.xaml.vb:

Private Sub AutoGeneratingColumn(sender As Object, e As DataGridAutoGeneratingColumnEventArgs)


        If e.PropertyName = "IsReadable" Or e.PropertyName = "HasValue" Then
            e.Cancel = True
            Exit Sub
        End If


      Dim oGrdTemplate As DataGridTemplateColumn = New DataGridTemplateColumn
        oGrdTemplate.Header = e.Column.Header               
        oGrdTemplate.CellTemplate = CType(grdTotal.FindResource("test"), DataTemplate)
        e.Column = oGrdTemplate

Expected: The above code works, but I have 40 columns so I have to duplicate the same DataTemplate for 40 times. I feel its not the better approach. I would like to bind the corresponding Column name as Col1, Col2, Col3 etc in every Columns. Its there a way to bind in Xaml well and good if not in code-behind is possible?

I tried with <DataTrigger Binding="{Binding Path=.}" Value="0,00"> does not work.

Upvotes: 1

Views: 281

Answers (2)

Sam
Sam

Reputation: 81

I have referred @themightylc answer then I have added the class cls_PMImageConverter, <local:cls_PMImageConverter x:Key="PMImageConverter"/>, <DataTemplate x:Key="colTemplate_Col1"> <Image Source="{Binding Path=Col1, Converter={StaticResource PMImageConverter}}" /> </DataTemplate> <DataTemplate x:Key="colTemplate_Col2"> <Image Source="{Binding Path=Col2, Converter={StaticResource PMImageConverter}}" /> </DataTemplate>

etc till col40

and called this template in AutogeneratedColumn event as

Dim oGrdTemplate As DataGridTemplateColumn = New DataGridTemplateColumn
 oGrdTemplate.Header = e.Column.Header
 oGrdTemplate.CellTemplate = CType(grdTotal.FindResource("colTemplate_"+e.PropertyName), DataTemplate)
 e.Column = oGrdTemplate `

It works.. But still, its not dynamic rite? Can I improve this code further??

Upvotes: 0

themightylc
themightylc

Reputation: 324

There is plenty room of improvement your design, for example you should have an Enumeration as your columns instead of 40 distinctive named objects.

But even with your current design, you can implement an IValueConverter that directly turns the value to the correct image URI and then you can bind the Image directly to your source Value through the converter.

Off the top of my head, untested:

Write a Converter:

<ValueConversion(GetType(Double), GetType(String))>
Public Class MyValueToImageConverter
    Implements IValueConverter

    Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
        Try
            If CDbl(value) = 0.0 Then Return "../Resources/pmIcons/minus-256.png"
            If CDbl(value) = 1.0 Then Return "../Resources/pmIcons/greenRoundTick.png"
            If CDbl(value) = 2.0 Then Return "../Resources/pmIcons/redCross.png"
        Catch ex As Exception
            'this is okay for our purpose
        End Try
        Return "../Resources/Help.png"
    End Function

    Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
        Throw New NotImplementedException()
    End Function
End Class

Embed in in your Resources (Window or Page etc)

<Window.Resources>
    <local:MyValueToImageConverter x:Key="myConverter"/>
</Window.Resources>

And bind your columns like this:

<Image Source="{Binding Col1,Converter={StaticResource myConverter}}" />

You can then wrap this functionality into a UserControl making use of the ominous "Tag" DependencyProperty

<UserControl
    x:Class="StatusIcon"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfApp1"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d"
    >
    <UserControl.Resources>
        <local:MyValueToImageSourceConverter x:Key="_conv" />
    </UserControl.Resources>
    <Image Source="{Binding Tag, RelativeSource={RelativeSource AncestorType={x:Type local:StatusIcon}}, Converter={StaticResource _conv}}" />
</UserControl>

And end up with something as neat and clean as this:

<local:StatusIcon Tag="{Binding Col1}"/>

You can then further improve this by replacing Tag with your own DependencyProperty called Value or something similar

Upvotes: 0

Related Questions