views:

1034

answers:

2

Greetings!

I ran into this problem in my project (Silverlight 3 with C#):

I have a TreeView which is data bound to, well, a tree. This TreeView has a HierarchicalDataTamplate in a resource dictionary, that defines various controls. Now I want to hide (Visibility.Collapse) some items depending on wether a node has children or not. Other items shall be visible under the same condition.

It works like charm when I first bind the source tree to the TreeView, but when I change the source tree, the visibility in the treeview does not change.

XAML - page:

<controls:TreeView x:Name="SankeyTreeView" 
  ItemContainerStyle="{StaticResource expandedTreeViewItemStyle}"
  ItemTemplate="{StaticResource SankeyTreeTemplate}">
    <controls:TreeViewItem IsExpanded="True">
        <controls:TreeViewItem.HeaderTemplate>
            <DataTemplate>
                <TextBlock Text="This is just for loading and will be replaced directly after the data becomes available..."/>
            </DataTemplate>
        </controls:TreeViewItem.HeaderTemplate>
    </controls:TreeViewItem>
</controls:TreeView>

XAML - ResourceDictionary

<!-- Each node in the tree is structurally identical, hence only one Hierarchical
     Data Template that'll use itself on the children. -->
<Data:HierarchicalDataTemplate x:Key="SankeyTreeTemplate" 
  ItemsSource="{Binding Children}">
    <Grid Height="24">
    <TextBlock x:Name="TextBlockName" Text="{Binding Path=Value.name, Mode=TwoWay}" 
      VerticalAlignment="Center" Foreground="Black"/>
    <TextBox x:Name="TextBoxFlow" Text="{Binding Path=Value.flow, Mode=TwoWay}"
      Grid.Column="1" Visibility="{Binding Children, 
        Converter={StaticResource BoxConverter}, 
        ConverterParameter=\{box\}}"/>
    <TextBlock x:Name="TextBlockThroughput" Text="{Binding Path=Value.throughput, Mode=TwoWay}" 
      Grid.Column="1" Visibility="{Binding Children, 
        Converter={StaticResource BoxConverter}, ConverterParameter=\{block\}}"/>
    <Button x:Name="ButtonAddNode"/>
    <Button x:Name="ButtonDeleteNode"/>
    <Button x:Name="ButtonEditNode"/>
    </Grid>
</Data:HierarchicalDataTemplate>

Now, as you can see, the TextBoxFlow and the TextBlockThroughput share the same space. What I aim at: The "Throughput" value of a node is how much of something 'flows' through this node from its children. It can't be changed directly, so I want to display a text block. Only leaf nodes have a TextBox to let someone enter the 'flow' that is generated in this leaf node. (I.E.: Node.Throughput = Node.Flow + Sum(Children.Throughput), where Node.Flow = 0 for each non-leaf.)

What the BoxConverter (silly name -.-) does:

public object Convert(object value, Type targetType, object parameter,
  System.Globalization.CultureInfo culture)
{
    if ((value as NodeList<TreeItem>).Count > 1) // Node has Children?
    {
        if ((parameter as String) == "{box}")
        {
            return Visibility.Collapsed;
        }
        else ((parameter as String) == "{block}")
        {
            return Visibility.Visible;
        }
    }
    else
    {
        /*
         * As above, just with Collapsed and Visible switched
         */
    }
}

The structure of the tree that is bound to the TreeView is essentially stolen from Dan Vanderboom (a bit too much to dump the whole code here), except that I here of course use an ObservableCollection for the children and the value items implement INotifyPropertyChanged.

I would be very grateful if someone could explain to me, why inserting items into the underlying tree does not update the visibility for box and block.

Thank you in advance!

A: 

What is happening is that Converter is called whenever the property is changed.

However adding items to a collection doesn't constitute changing the property. It is still the same collection after all. What you need to do is for the ViewModel to NotifyPropertyChanged when the collection changes. That'll cause the converter to re-evaluate the collection.

Graeme Bradbury
A: 

Hi.

I understand, that the converter is not called when the Collection is not changed, but if I change Child-Items the Main-Collection is not actually changed and thus I can't call NotifyCollectionChanged. (I could call it with the Reset-Option, but that closes all expanded Items)

I also can't call it on the Child-Collections, since they are bound EntityCollections which don't have such a Property.

Is there another way to refresh only a subtree of the items?