Silverlight: Define event handler in hierarchical data template

eventssilverlighttreeview

I am having problems getting at a click event of a button and am using Silverlight 3.0 w/ matching Silverlight Toolkit.

Problem

I have this TreeView:

TreeView sample http://a.imagehost.org/0939/TreeView.png.

The value for a certain node is the sum of the values of its children. Only in leaves can data be added (for the time being).
What I want to achieve is that a user can add (and eventually remove) entries in the tree to eventually create a custom diagram.
To that end I would like the "plus sign" to insert a new line / node as child of the node where the user clicked. (I.e. if I click the plus at "Display", I get a line below to specify CRT or TFT or whatever.)

Thing is, for all my brain is worth, I don't know how to receive any useful event.
The TextBlock, TextBox and Button are defined in a hierarchical template and I can't define a Click-handler in that template.

OTOH, I haven't found a way to get at the template items of a certain TreeViewItem from within (c#) code. Very well am I able to do trv.ItemContainerGenerator.GetContainerFromItem(item), and as Justin Angel showed I can very well change the font size, but didn't find any way to access the textbox or button.

Is there any way to capture the click event to the button? Or any alternative way of getting something that gives the "add below" functionality?

Thank you in advance.


More Data

The treeview xaml is this:

<controls:TreeView x:Name="SankeyDataTree" 
    ItemTemplate="{StaticResource SankeyTreeTemplate}" BorderThickness="0" 
    Background="{x:Null}" HorizontalAlignment="Left" VerticalAlignment="Top">
    <controls:TreeViewItem IsExpanded="True">
        <controls:TreeViewItem.HeaderTemplate>
            <DataTemplate>
                <TextBlock Text="Loading..."/>
            </DataTemplate>
        </controls:TreeViewItem.HeaderTemplate>
    </controls:TreeViewItem>
</controls:TreeView>

I use this HierarchicalDataTemplate (and stole the appraoch from Timmy Kokke):

<Data:HierarchicalDataTemplate x:Key="SankeyTreeTemplate" ItemsSource="{Binding Children}">
    <Grid Height="24">
        <Grid.ColumnDefinitions>
            <!-- ... -->
        </Grid.ColumnDefinitions>
        <TextBlock Text="{Binding Path=Value.name, Mode=TwoWay}" VerticalAlignment="Center"/>
        <TextBox Text="{Binding Path=Value.flow, Mode=TwoWay}" Margin="4,0" VerticalAlignment="Center" d:LayoutOverrides="Width" Grid.Column="1" TextAlignment="Right" Visibility="{Binding Children, Converter={StaticResource BoxConverter}, ConverterParameter=\{box\}}"/>
        <TextBlock Text="{Binding Path=Value.throughput, Mode=TwoWay}" Margin="4,0" VerticalAlignment="Center" d:LayoutOverrides="Width" Grid.Column="1" TextAlignment="Right" Visibility="{Binding Children, Converter={StaticResource BoxConverter}, ConverterParameter=\{block\}}"/>
        <Button Margin="0" Grid.Column="2" Style="{StaticResource TreeViewItemButtonStyle}">
            <Image Source="../Assets/add.png" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </Button>
    </Grid>
</Data:HierarchicalDataTemplate>

To this TreeView is bound a "SimpleTree", whose Values hold basically onle a string (name) and two doubles (flow and throughput).

public String name { get; set; }
public Double flow { get; set; }
public Double throughput { get; set; }

(Plus the code for the INotifyPropertyChanged to get a twoway bind to the text boxes.)

Best Answer

You can attach a Behavior to the Button in the HierarchicalDataTemplate and let that handle Click events from the Button.

Download and install the Expression Blend 3 SDK. Add a reference to System.Windows.Interactivity in the project and add a Behavior attached to a Button:

public class ButtonClickBehavior : Behavior<Button> {

  protected override void OnAttached() {
    base.OnAttached();
    AssociatedObject.Click += ButtonClick;
  }

  protected override void OnDetaching() {
    base.OnDetaching();
    AssociatedObject.Click -= ButtonClick;
  }

  void ButtonClick(object sender, RoutedEventArgs e) {
    Node node = AssociatedObject.DataContext as Node;
    if (node != null) {
      // Button clicked. Do something to associated node.
    }
  }

}

Attach the Behavior to the Button in the HierarchicalDataTemplate (assuming this namespace declaration: xmlns:interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"):

<Button Margin="0" Grid.Column="2" Style="{StaticResource TreeViewItemButtonStyle}">
  <Image Source="../Assets/add.png" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
  <interactivity:Interaction.Behaviors>
    <local:ButtonClickBehavior/>
  </interactivity:Interaction.Behaviors>
</Button>

If desired you can add properties to ButtonClickBehavior and set those from XAML to create a more reusable Behavior.

Related Topic