silverlightnesteddatatemplatevisualtreehelperfindancestor

If the DataTemplate is nested in another Datatemplate it's hard the binding with a father-template property


Have youI know that the problem has been many times discussed in the web. But mine is a particular case and I still haven't found the right solution.

Scenario: Silverlight 4 - A TreeView with data showed by two HierarchicalDataTemplate, one to show the first-level data (i.e. the data of the father-items of the TreeView), and one to show the second-level data (for the child-items). In the child-items template I have to bind the visibility of a control to a property of the data source class of the father template.

This is the XAML code:

<UserControl.Resources>
    <HierarchicalDataTemplate x:Key="modTreeArtDataParts2">
        <Grid>
            <TextBlock
                Visibility="{Binding ???}"/>
        </Grid>
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate x:Key="modTreeArtDataParts"
        ItemTemplate = "{StaticResource modTreeArtDataParts2}"
        ItemsSource = "{Binding RicambiItemList}">

    </HierarchicalDataTemplate>
</UserControl.Resources>

<Grid>
    <TreeView
        ItemTemplate = "{StaticResource modTreeArtDataParts}"
        ItemsSource="{Binding RicambiList}"/>
</Grid>

If it was WPF I could write:

Visibility = "{Binding DataContext.Ori, Converter={StaticResource rVisibilityConverter}, RelativeSource={RelativeSource AncestorLevel=2, AncestorType={x:Type TreeViewItem}, Mode=FindAncestor}}"

... and it would certainly works. But I know that in Silverlight FindAncestor as binding-mode with RealitiveSource is not supported. The solutions in the web are all around the scrolling down, in the code-behind, of the visual tree. It doesn't matter if it's realized with a Behavior or with an Attached-Propery. The solutions are like this:

Public Class hideTextBlockBehavior
    Inherits Behavior(Of DependencyObject)

    Protected Overrides Sub OnAttached()
        MyBase.OnAttached()
        Dim g As Grid = FindVisualParent(Of Grid)(AssociatedObject)
        Dim o As customType = g.DataContext
        If o.hide Then AssociatedObject.Visibility = Visibility.Collapsed
    End Sub

    Private Function FindVisualParent(Of parentItem As DependencyObject)(ByVal obj As DependencyObject) As parentItem
        Dim objParent As DependencyObject = obj
        While obj Is Nothing = False AndAlso TypeOf obj Is parentItem = False
            obj = VisualTreeHelper.GetParent(obj)
        End While
        Return DirectCast(obj, parentItem)
    End Function
End Class

<HierarchicalDataTemplate x:Key="modTreeArtDataParts2">
    <Grid>
        <TextBlock>
            <i:Interaction.Behaviors>
                <il:hideTextBlockBehavior/>
            </i:Interaction.Behaviors>
        </TextBlock>
    </Grid>
</HierarchicalDataTemplate>

I used many times solutions like this, and they always works. But in this case my DataTemplate is nested into another DataTemplate then, when I'm in the "OnAttached" method, the property "Parent" of the "AssociatedObject" is nothing, then I have no Visual-Tree to scroll.

Have you got a suggestion? Thank you in advance! Pileggi


Solution

  • My suggestion would be to pass a reference to your parent view model to the children on construction:

    var itemVm = new ItemViewModel()
    {
        Description = "Parent", ChildVisibility = "Collapsed"
    }
    itemVm.Children = new List<ChildItemViewModel>
    {
        new ChildItemViewModel()
        {
            ParentVm = itemVm;
            Description = "Child"
        }
    }
    

    By doing so, you can easily bind to the property on the parent view model like so:

    <TextBlock Visibility="{Binding ParentVM.ChildVisibility}"/>