Reusable DataGridTemplateColumn

Sep 4, 2008 at 5:05 PM
Hi,
First of all: great job!

I've a problem with DataGridTemplateColumn: 
i've define a datagrid with few DataGridTemplateColumns..Each column defines a CellTemplate that reference a staticresource called defaultCellTemplate
I have 12 columns that i want to bind with a dataset with 12 columns. How can i define the binding of each column?

Have I to define twelve identical DataTemplate in the resources (and change only the binding path), or exists a (faster and better) way?

Thanks in advance
Marco Roello

CELL TEMPLATE:

<

 

DataTemplate x:Key="defaultCellTemplate" >

 

 

 

<Border BorderBrush="#FFFFFFFF" BorderThickness="1,1,1,1" CornerRadius="4,4,4,4">

 

 

 

<Border x:Name="border" Background="#7F000000" BorderBrush="#FF000000" BorderThickness="1,1,1,1" CornerRadius="4,4,4,4">

 

 

 

<Grid>

 

 

 

<Grid.RowDefinitions>

 

 

 

<RowDefinition Height="0.507*"/>

 

 

 

<RowDefinition Height="0.493*"/>

 

 

 

</Grid.RowDefinitions>

 

 

 

<Border Opacity="0" HorizontalAlignment="Stretch" x:Name="glow" Width="Auto" Grid.RowSpan="2" CornerRadius="4,4,4,4">

 

 

 

<Border.Background>

 

 

 

<RadialGradientBrush>

 

 

 

<RadialGradientBrush.RelativeTransform>

 

 

 

<TransformGroup>

 

 

 

<ScaleTransform ScaleX="1.702" ScaleY="2.243"/>

 

 

 

<SkewTransform AngleX="0" AngleY="0"/>

 

 

 

<RotateTransform Angle="0"/>

 

 

 

<TranslateTransform X="-0.368" Y="-0.152"/>

 

 

 

</TransformGroup>

 

 

 

</RadialGradientBrush.RelativeTransform>

 

 

 

<GradientStop Color="#B28DBDFF" Offset="0"/>

 

 

 

<GradientStop Color="#008DBDFF" Offset="1"/>

 

 

 

</RadialGradientBrush>

 

 

 

</Border.Background>

 

 

 

</Border>

 

 

 

<TextBlock Name="textNumber" Margin="2,2,2,2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="Auto" Grid.RowSpan="2" Foreground="Gold">

 

 

 

<TextBlock.Text>

 

 

 

<Binding StringFormat="{}{0:N2}" />

 

 

 

</TextBlock.Text>

 

 

 

</TextBlock>

 

 

 

<Border HorizontalAlignment="Stretch" Margin="0,0,0,0" x:Name="shine" Width="Auto" CornerRadius="4,4,0,0">

 

 

 

<Border.Background>

 

 

 

<LinearGradientBrush EndPoint="0.494,0.889" StartPoint="0.494,0.028">

 

 

 

<GradientStop Color="#99FFFFFF" Offset="0"/>

 

 

 

<GradientStop Color="#33FFFFFF" Offset="1"/>

 

 

 

</LinearGradientBrush>

 

 

 

</Border.Background>

 

 

 

</Border>

 

 

 

</Grid>

 

 

 

</Border>

 

 

 

</Border>

 

 

 

</DataTemplate>

 

GRID DEFINITION:

<

 

local:DataGrid Name="MainGrid" Margin="10" RowHeight="80" HorizontalContentAlignment="Stretch" HorizontalScrollBarVisibility="Auto" VerticalContentAlignment="Stretch" AutoGenerateColumns="False" Background="Transparent" CellStyle="{StaticResource defaultCellStyle}" RowStyle="{StaticResource defaultRowStyle}" ColumnWidth="80" HorizontalGridLinesBrush="Transparent" VerticalGridLinesBrush="Transparent">

 

 

 

<local:DataGrid.Columns>

 

 

 

<local:DataGridTemplateColumn CellTemplate="{StaticResource defaultCellTemplate}" CellEditingTemplate="{StaticResource defaultCellEditingTemplate}" Width="100" x:Name="ColumnRpm" />

 

 

 

<local:DataGridTemplateColumn CellTemplate="{StaticResource defaultCellTemplate}" CellEditingTemplate="{StaticResource defaultCellEditingTemplate}" Width="*" x:Name="ColumnTps01" />

 

 

 

<local:DataGridTemplateColumn CellTemplate="{StaticResource defaultCellTemplate}" CellEditingTemplate="{StaticResource defaultCellEditingTemplate}" Width="*" x:Name="ColumnTps02" />

 

 

 

<local:DataGridTemplateColumn CellTemplate="{StaticResource defaultCellTemplate}" CellEditingTemplate="{StaticResource defaultCellEditingTemplate}" Width="*" x:Name="ColumnTps03" />

 

 

 

<local:DataGridTemplateColumn CellTemplate="{StaticResource defaultCellTemplate}" CellEditingTemplate="{StaticResource defaultCellEditingTemplate}" Width="*" x:Name="ColumnTps04" />

 

 

 

<local:DataGridTemplateColumn CellTemplate="{StaticResource defaultCellTemplate}" CellEditingTemplate="{StaticResource defaultCellEditingTemplate}" Width="*" x:Name="ColumnTps05" />

 

 

 

<local:DataGridTemplateColumn CellTemplate="{StaticResource defaultCellTemplate}" CellEditingTemplate="{StaticResource defaultCellEditingTemplate}" Width="*" x:Name="ColumnTps06" />

 

 

 

<local:DataGridTemplateColumn CellTemplate="{StaticResource defaultCellTemplate}" CellEditingTemplate="{StaticResource defaultCellEditingTemplate}" Width="*" x:Name="ColumnTps07" />

 

 

 

<local:DataGridTemplateColumn CellTemplate="{StaticResource defaultCellTemplate}" CellEditingTemplate="{StaticResource defaultCellEditingTemplate}" Width="*" x:Name="ColumnTps08" />

 

 

 

<local:DataGridTemplateColumn CellTemplate="{StaticResource defaultCellTemplate}" CellEditingTemplate="{StaticResource defaultCellEditingTemplate}" Width="*" x:Name="ColumnTps09" />

 

 

 

<local:DataGridTemplateColumn CellTemplate="{StaticResource defaultCellTemplate}" CellEditingTemplate="{StaticResource defaultCellEditingTemplate}" Width="*" x:Name="ColumnTps10" />

 

 

 

<local:DataGridTemplateColumn CellTemplate="{StaticResource defaultCellTemplate}" CellEditingTemplate="{StaticResource defaultCellEditingTemplate}" Width="*" x:Name="ColumnTps11" />

</
local:DataGrid.Columns>

</
local:DataGrid>


 

Coordinator
Sep 8, 2008 at 5:48 PM
If you have a standard template set for every cell like you do in the example above, one thing you can do is write a custom TemplateColumn class that knows how to bind to the correct visual.  For example, in your DataTemplate for the CellTemplate, you have a TextBlock there.  If that is what I am looking to bind to, I can create a custom Template Class like this:

public

 

class DataGridCustomTemplateColumn : DataGridTemplateColumn
{
    private BindingBase _dataFieldBinding;
    public virtual BindingBase DataFieldBinding
    {
        get { return _dataFieldBinding; }
        set { _dataFieldBinding = value; }
    }

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        FrameworkElement template = base.GenerateElement(cell, dataItem);
        TextBlock tb = Helper.GetVisualChild<TextBlock>(template);
        BindingOperations.SetBinding(tb, TextBlock.TextProperty, DataFieldBinding); 
        return template;
    }
}

 

then in my xaml, I can just declare the column like so:

<

 

local:DataGridCustomTemplateColumn Header="CustomTemplate" DataFieldBinding="{Binding Path=FirstName}">
    <local:DataGridCustomTemplateColumn.CellTemplate>
        <DataTemplate>
            ...
        </DataTemplate>
    </local:DataGridCustomTemplateColumn.CellTemplate>
</local:DataGridCustomTemplateColumn>

 





Sep 9, 2008 at 8:23 AM

Thanks Vinsibal,

last question: can I achieve this only in xaml?
I'll explain better:
There is a way to use a Style Setter or Trigger Setter to Bind a property of an object in the visual tree of the datatemplate or control template, or the only way is in code.

In my opinion it is very useful to allow a UI Designer to write templates without thinking on wich properties will be binded, and only in a second step will determine the behaviour with other objects.

Regards

Marco

Coordinator
Sep 9, 2008 at 5:48 PM
If you don't want to create a binding subclass for a template column, you can use a stock column and retemplate that so that you get the binding for free or you can just create separate templates for each template column.
Feb 9, 2009 at 2:29 PM

Hi Vinsibal,

Your DataGridCustomTemplateColumn class was exactly what I was looking for. Unfortunately I'm having trouble with the GetVisualChild helper method.  I did give it a try using the 

 

VisualTreeHelper class but can't seem toget it to work.  The GetChildrenCount is always zero.  Could you post a working sample?

Thanks,
Margaret