4

I'm using WPF with .NET 3.0.

I have a relatively simple DataTemplate defined as the CellTemplate for a GridView. I expect the DataTemplate's VisualTree property to contain a FrameworkElementFactory, but the property is null when I try to access it from the GridViewColumnHeader.Click event. Why is the VisualTree null? I need to access it. Here is the ListView definition:

<ListView ItemsSource="{Binding Stuff}" GridViewColumnHeader.Click="Header_Click">
    <ListView.View>
        <GridView>
            <GridViewColumn Width="28">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <Image Name="statusImage" Width="16" Height="16" Source="../Images/media_play_green_16x16.png"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

And here is the event handler:

private void Header_Click(object sender, RoutedEventArgs e)
{
    GridViewColumnHeader gvch = e.OriginalSource as GridViewColumnHeader;

    // error! VisualTree is null!
    //gvch.Column.CellTemplate.VisualTree.GetType(); 
}
Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
atoumey
  • 2,536
  • 2
  • 20
  • 16
  • Could you tell us why you need to access the template's visual tree ? There might be a better way to achieve what you want to do... However I'm curious to know why it's null, that's quite surprising... – Thomas Levesque Mar 30 '10 at 21:07
  • The short version is that I want to call VisualTree.SetBinding(FrameworkElement.DataContextProperty, new Binding("Item")); The purpose of that is to cause all data binding in the cell template to become relative to the property "Item" on the actual item in the ItemsSource. – atoumey Mar 30 '10 at 21:10

2 Answers2

7

This is the known and expected behaviour. I can't find a MSDN or other "authoritative" citation right now, but this MSDN forums post explains (sort of!):

FrameworkTemplate.VisualTree property ... is mainly used when you programmatically create DataTemplate/ControlTemplate in code, When defining DataTemplate/ControlTemplate using XAML, this property will be null, because WPF uses another mechanism to instantiate and construct XAML generated templates. (emphasis added)

So the VisualTree property is not populated when a template is loaded from XAML: it is populated only if you construct the template in code using FrameworkElementFactory.

To get the content of a template defined in XAML, call FrameworkTemplate.LoadContent(). This will materialise an instance of the template and give you the root element -- you can then drill in as required and set properties or bindings. It is up to you to slot the materialised instance into the containing window or control's visual tree though, so you will probably want to encapsulate this!

itowlson
  • 73,686
  • 17
  • 161
  • 157
  • Thanks. Do you know of any articles explaining how to insert loaded templates on the fly into an ItemsControl? I'd like to call LoadContent() on the CellTemplate of a GridViewColumnHeader and insert the result into the cell in the ListView. – atoumey Mar 31 '10 at 14:02
  • Sorry, atourney, I'm afraid not. I thought I had a sample of this from an old project but I can't find it any more, and that was in a quite different context anywhere. My suspicion is you would need to subclass ListView and override GetContainerForItemOverride to return a subclass of ListViewItem, then put the code into that subclass of ListViewItem -- but I haven't tested this. – itowlson Mar 31 '10 at 20:40
  • Thanks. I've opened a new question for this: http://stackoverflow.com/questions/2553964/how-do-i-manually-manage-the-generation-of-cell-visuals-with-a-gridviewcolumn-cel – atoumey Mar 31 '10 at 20:43
0

The reason behind Of Visual Tree being null is because Visual Tree property is closer to Logical Tree rather than Visual One. Actual content of the Template is stored in TemplateContent object which has no public members, You will have to use LoadContent method.