views:

335

answers:

1

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(); 
}
+3  A: 

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
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
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
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