WindowsPhoneGeek

WPAppInfo

Login | Join (Why?)

rss rss rss
logo

How to access a Control placed inside ListBox ItemTemplate in WP7

published on: 3/23/2011 | Views: N/A | Tags: ListBox

by WindowsPhoneGeek

In this post I am going to talk about how to access a Control inside the ListBox ItemPanelTemplate/DataTemplate in Silverlight for WP7.

Question: How to access/modify a specific Control placed inside ListBox ItemTemplate/DataTemplate?

When you have a data bound control, lets say for example ListBox we usually add some custom DataTemplate. So sometimes you try to access and modify any element inside DataTemplate. 

Answer: Actually you can this by using the VisualTreeHelper which provides utility methods that can used to traverse object relationships (along child object or parent object axes) in the Silverlight for WP7 visual tree.

To begin with lets create a sample Windows Phone 7 project , add a data bound to a collection of strings ListBox  with the following ItemsTemplate and ItemsPanel:

<ListBox x:Name="list">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <ToggleButton x:Name="btnToggle"/>
                <CheckBox x:Name="cbx"/>
                <TextBlock Text="{Binding}"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
List<string> dataSource = new List<string> {"Item1","Item2","Item3" };
this.list.ItemsSource = dataSource;

How to Access a specific Control placed inside  ListBox ItemsTemplate

Here is how you can implement a Generic method that can find the first element from any particular type inside the Visual Tree:

Example1:  Use a Generic method to find first element of particular type:

private T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject
{
    var count = VisualTreeHelper.GetChildrenCount(parentElement);
    if (count == 0)
        return null;

    for (int i = 0; i < count; i++)
    {
        var child = VisualTreeHelper.GetChild(parentElement, i);
        
        if (child != null && child is T)
        {
            return (T)child;
        }
        else
        {
            var result = FindFirstElementInVisualTree<T>(child); 
            if (result != null)
                return result;
          
        }
    }
    return null;
}

Sample usage:

We will first get an instance of the second Listbox item using ItemContainerGenerator. (Note that we have to use ItemContainerGenerator because our ListBox is databound!). Next we will find the CheckBox control which is inside the ListBox itema and will set its IsChecked property to true:

ListBoxItem item = this.list.ItemContainerGenerator.ContainerFromIndex(2) as ListBoxItem;
CheckBox tagregCheckBox = FindFirstElementInVisualTree<CheckBox>(item);
tagregCheckBox.IsChecked = true;

Example2:  Use a simple method to find first element of a particular type that meets a condition:

private void SearchVisualTree(DependencyObject targetElement)
{
    var count = VisualTreeHelper.GetChildrenCount(targetElement);
    if (count == 0)
        return;

    for (int i = 0; i < count; i++)
    {
        var child = VisualTreeHelper.GetChild(targetElement, i);
        if (child is TextBlock)
        {
            TextBlock targetItem = (TextBlock)child;
            
            if (targetItem.Text == "Item2")
            {
                targetItem.Foreground = new SolidColorBrush(Colors.Green);
                return;
            }
        }
        else
        {
            SearchVisualTree(child);
        }
    }
}

Sample usage:

This code will find the first TextBlock element in the ListBox which has Text set to "Item2"

SearchVisualTree(this.list);

NOTE: In this way you can implement your own methods that find all element in the VisualTree of  a type,  you can add another condition, etc.

I hope that the post was helpful. The full source code is available here.

You can also follow us on Twitter @winphonegeek

Comments

Excellent

posted by: dSharp on 3/31/2011 4:28:29 AM

This is exactly what I needed; in the middle of developing a WP7 app and I needed to figure out how to access a control inside of a listboxitem; great job!

Great Tip!

posted by: Robert Hellestrae on 4/15/2011 1:25:43 AM

Similar scenario - except trying to access a TextBlock. Thanks!

Spot on, exactly what I needed :)

posted by: Sacha on 5/1/2011 3:35:23 AM

Last post went a bit odd, please delete :) Here is fixed version.

 Private Sub SearchVisualTree(ByVal targetElement As DependencyObject, ByVal ValuePropertyName As String, ByVal ValueToFind As Object, ByVal PropertyToUpdateName As String, ByVal PropertyToUpdateValue As Object)

        Dim count = VisualTreeHelper.GetChildrenCount(targetElement)

        If count = 0 Then

            Return

        End If

        For i As Integer = 0 To count - 1

            Dim child = VisualTreeHelper.GetChild(targetElement, i)

            If TypeOf child Is Image Then

                Dim targetItem As Image = DirectCast(child, Image)

                'Get the property value.
                Dim PropValue As Object = GetType(Image).GetProperty(ValuePropertyName).GetValue(targetItem, Nothing)

                'Is the value set and if so is it equal.
                If (PropValue IsNot Nothing AndAlso PropValue.Equals(ValueToFind)) Then

                    'Set the value on the target property.
                    Call GetType(Image).GetProperty(PropertyToUpdateName).SetValue(targetItem, PropertyToUpdateValue, Nothing)

                    Return

                End If

            Else

                Call SearchVisualTree(child, ValuePropertyName, ValueToFind, PropertyToUpdateName, PropertyToUpdateValue)

            End If

        Next

    End Sub

RE:Spot on, exactly what I needed

posted by: winphonegeek on 5/1/2011 10:33:38 AM

@Sacha Thank you for sharing you sample with the community.

The better way

posted by: Rui Figueiredo on 7/27/2011 7:41:12 PM

You can use LINQ, is the better and easy way to do this! All that code behind can be substituted by this 2 lines:

ListBoxItem item = this.list.ItemContainerGenerator.ContainerFromIndex(2) as ListBoxItem; item.GetVisualDescendants().OfType().First();

Thank a lot

posted by: Guillaume on 7/28/2011 12:18:59 PM

Thank for this code, it's save my life :D

the better way does not work WP7

posted by: dr memals on 9/6/2011 2:03:03 PM

@Rui Figueiredo

GetVisualDescendants

is not available in WP7 :(

Excellent

posted by: Raffaele Amodio on 9/7/2011 12:20:29 PM

Good Post!!!! Cheers!!!!

Thanks!

posted by: Alireza on 10/25/2011 6:40:55 PM

Great post. Thank you!

Thanks

posted by: Nathan on 11/13/2011 9:33:59 PM

Would you be able to update this with an example of searching for the a control name?

thanks

RE

posted by: Nathan on 11/14/2011 7:27:55 PM

Hi Mr WPG!

This is the code i have slightly edited from above, the hope is to find the textblock name instead of it's contents. I'm unsure on how to call it, what item to pass it in the targetElement? regards, Nathan

  private void SearchVisualTree(DependencyObject targetElement, string controlName)
    {
        var count = VisualTreeHelper.GetChildrenCount(targetElement);
        if (count == 0)
            return;

        for (int i = 0; i < count; i++)
        {
            var child = VisualTreeHelper.GetChild(targetElement, i);
            if (child is TextBlock)
            {
                TextBlock targetItem = (TextBlock)child;

                if (targetItem.Name == controlName)
                {
                   // Do Something
                    return;
                }
            }
            else
            {
                SearchVisualTree(child, controlName);
            }
        }
    }

RE: @Nathan

posted by: winphonegeek on 11/16/2011 2:44:01 PM

Since what you want to do is to find a TextBlock which is a child of one of the items in a list box, you have to first find the list box item. Then you can search in its children (using your version of the SearchVisualTree method) for the TextBlock like in the snippet below:

// here we always get the 2nd item, in an actual app we will usually
// have some additional code to find the right list box item
ListBoxItem listBoxItem= this.list.ItemContainerGenerator.ContainerFromIndex(2) as ListBoxItem;
TextBlock myTextBlock = SearchVisualTree(listBoxItem, "name of text block");

NOTE: you will probably want your SearchVisualTree method to have a return type of TextBlock instead of void.

Binding SQL CE element to a ListBox Item

posted by: Mis Moisei on 11/28/2011 2:22:53 PM

How can I bind the< TextBlock Text="{Binding}"/> to the database ?

public IList<Product> GetProducts()
        {
            IList<Product> listaProducts = null;
            using (AparateDataContext context = new AparateDataContext(ConnectionString))
            {
                IQueryable<Product> query = from c in context.Product select c;
                listaProducts = query.ToList();
            }
            return listaProducts;
        }

 private void ShowDBinListbox_Click(object sender, EventArgs e)
        {
            IList<Product> products = this.GetProducts();
            that_xaml_textblock.Text = produs.Denumire;
        }

Can I search Control in PanoramaItem HeaderTemplate

posted by: Happyboy on 5/7/2012 4:42:34 AM

As the Title, I want to access a icon at headerTemplate. Is it able to do this. Just replace list to PanoItem.HeaderTemplate?

Add comment to 'How to access a Control placed inside ListBox ItemTemplate in WP7'

Comment

Our Top Articles & Free books

Our Top Tips & Samples