Template for WPF DataGridTextColumn ElementStyle and EditElementStyle with Binding

KyleLib picture KyleLib · Jan 15, 2013 · Viewed 8.4k times · Source

I have a WPF DataGrid that has 10 DataGridTextColumns displaying numeric data that require identical formatting. I want the EditingElementStyle number formatting (raw decimal or float) to be different than the ElementStyle formatting (formatted percent or money). If it matters, the DataContext of my grid is a CollectionViewSource.

I'd like to come up with a reusabe Style or Template resource to define my columns if possible. The XAML for my 10 DataGridTextColumns is nearly identical. I can't quite figure out how to use TemplateBinding, Element binding or RelativeSource binding in my template to ensure that each column gets the correct binding once templates are resolved.

My ultimate goal is to be able to define my DataGridTextColumns as follows:

<DataGridTextColumn x:Name="dingCutoffPctColumn" 
                    Binding="{Binding CutoffPct}" Header="Cutoff %" Width="60"
                    ElementStyle="{StaticResource NumberElementStyle}"
                    EditingElementStyle="{StaticResource EditErrorStyle}" />

Here's a representation of the working XAML that I'm currently using:

<DataGrid x:Name="myDataGrid" AutoGenerateColumns="False" 
          Margin="10,67,13,0" Height="200" EnableRowVirtualization="True"
          ItemsSource="{Binding}" VerticalAlignment="Top">
    <DataGrid.Resources>
        <Style x:Key="EditErrorStyle" TargetType="{x:Type TextBox}">
            <Setter Property="Padding" Value="-2"/>
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Setter Property="Background" Value="Red"/>
                    <Setter Property="ToolTip" 
                            Value="{Binding RelativeSource={RelativeSource Self},
                                    Path=(Validation.Errors)[0].ErrorContent}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
        <Style x:Key="NumberElementStyle" TargetType="{x:Type TextBlock}">
            <Setter Property="TextAlignment" Value="Right"/>
        </Style>
    </DataGrid.Resources>

    <DataGrid.Columns>
        <DataGridTextColumn x:Name="id" Binding="{Binding ID}" 
                            Visibility="Collapsed" />
        <DataGridTextColumn x:Name="name" Header="Name"
                            Binding="{Binding Name, 
                                      TargetNullValue=&lt;enter new name&gt;}" />

        <DataGridTextColumn x:Name="cutoffPct" {Binding CutoffPct}" 
                            Header="Cutoff %" Width="60">
            <DataGridTextColumn.ElementStyle>
                <Style TargetType="{x:Type TextBlock}" 
                       BasedOn="{StaticResource NumberElementStyle}">
                    <Setter Property="Text" 
                            Value="{Binding CutoffPct, StringFormat=P}"/>
                </Style>
            </DataGridTextColumn.ElementStyle>
            <DataGridTextColumn.EditingElementStyle>
                <Style TargetType="{x:Type TextBox}" 
                       BasedOn="{StaticResource EditErrorStyle}">
                    <Setter Property="Text" 
                            Value="{Binding CutoffPct, 
                                ValidatesOnExceptions=True, StringFormat=\{0\}}"/>
                </Style>
            </DataGridTextColumn.EditingElementStyle>
        </DataGridTextColumn>
      </DataGrid.Columns>
</DataGrid>

Thanks for your help

Answer