How to use a button within a List Item

One of the problems with Silverlight is that the templating mechanism is really good but you can quickly get a bit stuck. I ran into one such example when I had created a nice DataTemplate for a ListBoxItem that contained a button. When the button is clicked I wanted a specific action to take place in the context of the containing list box item, i.e. I wanted the list box item to be selected because the user has pressed a button within the item.

<DataTemplate x:Key="MyDataTemplate">

     <Grid>

       <Button Content="Edit" Click="Button_Click" />

     </Grid>

</DataTemplate>

 

The problem is that the Button_Click event will fire but none of the event args will explain which of the potentially many buttons has been pressed. WPF uses tricks such as binding the button’s tag to an ancestor element but SL2 doesn’t (I believe) offer this feature. One solution is to skip the button click event and simulate the button via some mouse down events and event bubbling but that seemed too dirty for me. So I thought I could walk the control tree and find which ListBoxItem the button was within. You have to be a bit careful here because templating/themes can introduce a different logical tree so you must walk the tree looking for a ListBoxItem rather than assuming a specific number of hops. BTW, in theory the ListBoxItem itself may have been “styled” out too so you should degrade gracefully if you can’t find the ListBoxItem.

So I wrote some code to loop and walk the FrameworkElement.Parent properties. This didn’t work since the .Parent returned null at the ContentPresenter boundary, i.e. before the ListBoxItem. Still not sure exactly why that is, but I needed a quick solution so I turned to the Visual tree instead. This proved to be the solution…

private void Button_Click(object sender, RoutedEventArgs e)

{

 

    Button buttonSender = sender as Button;

    // which item is containing the button?

    DependencyObject currentElement = buttonSender;

    ListBoxItem selectedItem = currentElement as ListBoxItem;

    DependencyObject theParent = VisualTreeHelper.GetParent(currentElement);

    while (selectedItem == null && theParent != null)

    {               

        currentElement = theParent;

        selectedItem = theParent as ListBoxItem;

        theParent = VisualTreeHelper.GetParent(currentElement);

    }

 

    // if we have found an item then ensure it is selected

    if (selectedItem != null)

    {

        selectedItem.IsSelected = true;

    }

 

}

 

 

Thanks to Keith Mohoney’s Post for the information about the Visual Tree Helper

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s