views:

3416

answers:

1

I'm having a problem understanding the basics of databinding in WPF. I have a generic DataGrid (with AutoGenerateColumns set) that is bound to a DataTable with column names that vary on every load. When the dataTable contains columns that are of type boolean, I want to render a column that contains custom images representing true and false.

To accomplish this, I have a StaticResource declared on the page for the celltemplate, and I have c# code that traps the AutoGenerateColumn event and uses this template:

    <DataTemplate x:Key="CheckmarkColumnTemplate">
        <Image x:Name="CheckmarkImage" Source="..\..\images\check.png" Height="16" Width="16" />
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value}" Value="False">
                <Setter TargetName="CheckmarkImage" Property="Source" Value="..\..\images\nocheck.png" />
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>

C# code:

    private void dgData_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        if (e.PropertyType == typeof(bool))
        {
            DataGridTemplateColumn col = new DataGridTemplateColumn();
            Binding binding = new Binding(e.PropertyName);
            col.CellTemplate = (this.Resources["CheckmarkColumnTemplate"] as DataTemplate);
            col.Header = e.PropertyName;
            e.Column = col;
        }
    }

This mostly works, except I've got the DataTrigger Binding property messed up. It never detects when the value of the column is "false", so it never shows the nocheck.png image. I don't know how to write the Binding property so that's referencing the databound value of the column (remember, the column name is different every time, so I can't hard-code a column name in the Path part of the binding).

Can anyone tell me what the Binding property should look like so that it just grabs the value of the column?

+1  A: 

I achieved the result I was after by using a different method. Instead of using a DataGridTemplateColumn, I used a DataGridCheckBoxColumn and set a custom ElementStyle based off the sample style used in the WPF Toolkit's "Hands-On Lab":

    <Style x:Key="NoBorderCheckBoxStyle" TargetType="{x:Type CheckBox}">
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="Background" Value="{StaticResource CheckBoxFillNormal}"/>
        <Setter Property="BorderBrush" Value="{StaticResource CheckBoxStroke}"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="FocusVisualStyle" Value="{StaticResource EmptyCheckBoxFocusVisual}"/>
        <Setter Property="HorizontalAlignment" Value="Center"/>
        <Setter Property="IsEnabled" Value="false"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type CheckBox}">
                    <BulletDecorator SnapsToDevicePixels="true" Background="Transparent">
                        <BulletDecorator.Bullet>
                            <Canvas x:Name="canvas"  Width="16" Height="16" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5">
                                <Image x:Name="checkImage" Source="..\..\images\check.png" Height="16" Width="16"></Image>
                            </Canvas>
                        </BulletDecorator.Bullet>
                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RecognizesAccessKey="True"/>
                    </BulletDecorator>
                    <ControlTemplate.Triggers>
                        <Trigger Property="HasContent" Value="True">
                            <Setter Property="FocusVisualStyle" Value="{StaticResource CheckRadioFocusVisual}"/>
                            <Setter Property="Padding" Value="4,0,0,0"/>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                        <Trigger Property="IsChecked" Value="False">
                            <Setter Property="Source" TargetName="checkImage" Value="..\..\images\nocheck.png" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

I had problems reading the "IsEnabled" property from the actual DataGrid column settings (its property is "IsReadOnly") but because my use of the DataGrid is read-only, I just set it to false here.

DrBoom