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

10.5k views Asked by At

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

2

There are 2 answers

3
123 456 789 0 On BEST ANSWER

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>
0
Alternator On

My problem of trying to bind to the GridViewColumn appears to be two-fold:

  • Firstly the GridViewColumn can only provide one resultant value (probably the first item in the itemssource) as opposed to a value on a per row basis.

  • Secondly the GridViewColumn does not appear to exist in the visualtree and so is not available for binding to.

Further research shows that to bind to properties of the GridViewColumn, the following syntax can be used:

<TextBlock Text="{Binding Path=View.Columns[0].Header, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}" />

Obtained from MSDN: Passing a parameter into a CellTemplate specified in a GridViewColumn