Search code examples
wpftemplatesbindinggridviewcolumn

How to bind to a property on a gridviewcolumn from its celltemplate


The general problem I want to solve is to have just one datatemplate for a checkbox which I can then use for many different columns in a listview (using a gridview). In all examples I've seen a seperate template is created for each binding which seems overkill to me.

I've been trying to do this by creating an attached property that the gridviewcolumn will set. Then I can simply have one datatemplate for a checkbox that binds to that attached property.

The problem I'm having is actually setting the checkbox source to the gridviewcolumn.

Here is the xaml:

<DataTemplate x:Key="CheckBoxTemplate">
    <CheckBox IsChecked="{Binding Path=(ap:AttachedProperties.IsChecked),
        RelativeSource={RelativeSource AncestorType={x:Type GridViewColumn}}}" />
</DataTemplate>

<GridView x:Key="MyGridView">
    <GridViewColumn Header="CheckBox" CellTemplate="{StaticResource CheckBoxTemplate}" ap:AttachedProperties.IsChecked="{Binding Path=SomeValue}" />
</GridView>

P.S. The Attached property is working fine, I've attached it directly to the checkbox and used a relativesource self binding and gotten the values coming through, but when I try to bind it on the GridViewColumn I get no happiness, in fact I haven't been able to bind to the Header on the GridViewColumn either...

P.P.S I have tried other binding source expressions as well (just not the right one it seems)...

Edit: Immediately after posting this it dawned on me that the GridViewColumn exists for all rows and so that is probably why this isn't working?!

I've slept on it now and realise that doing things in this way wont work (because the GridViewColumn can only hold the value for the first row not each row as I would need it to) - however I still would have thought it possible to bind to the GridViewColumn?

Here is a xaml only example to show the behaviour:

<Window x:Class="WpfApplication3.MainWindow"
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       Title="MainWindow"
       Width="525"
       Height="350">
   <Grid>
       <ListView Name="listView1"
                 Width="479"
                 Height="287"
                 Margin="12,12,0,0"
                 HorizontalAlignment="Left"
                 VerticalAlignment="Top">
           <ListView.View>
               <GridView>
                   <GridViewColumn Header="A Header">
                       <GridViewColumn.CellTemplate>
                           <DataTemplate>
                               <StackPanel>
                                   <TextBlock Text="{Binding Path=Header, RelativeSource={RelativeSource AncestorType={x:Type GridViewColumn}}}" />
                                   <TextBlock Text="Visible row" />
                               </StackPanel>
                           </DataTemplate>
                       </GridViewColumn.CellTemplate>
                   </GridViewColumn>
               </GridView>
           </ListView.View>
           <ListViewItem />
           <ListViewItem />
       </ListView>
   </Grid>
</Window>

Under such a scenerio I would expect to see "A Header" just above each "Visible row" text


Solution

  • I've check snoop, the reason why that is not working because GridColumnHeader is not in the VisualTree where the GridRows are. My solution is to use ElementName and bind it to the Header property. Fairly simple, much cleaner and readable.

        <ListView Name="listView1"
                 Width="479"
                 Height="287"
                 Margin="12,12,0,0"
                 HorizontalAlignment="Left"
                 VerticalAlignment="Top">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="A Header" x:Name="HeaderOne">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <StackPanel>
                                    <TextBlock Text="{Binding ElementName=HeaderOne,Path=Header}" />
                                    <TextBlock Text="Visible row" />
                                </StackPanel>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
            <ListViewItem />
            <ListViewItem />
        </ListView>