Getting the control inside a DataTemplate

Here is one way we can get to the Control inside a DataTemplate

lets start with the following XAML in the page

<UserControl x:Class=”SilverlightApplication1.Page”
    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml
    xmlns:local=”clr-namespace:SilverlightApplication1;assembly=SilverlightApplication1″
    Width=”400″ Height=”300″>
    <UserControl.Resources>
        <DataTemplate x:Key=”dt”>
            <local:Product Margin=”2″/>
        </DataTemplate>
    </UserControl.Resources>
    <Canvas>
        <StackPanel>
            <ListBox Height=”300″  x:Name=”list1″ Margin=”100,100,100,20″ ItemTemplate=”{StaticResource dt}”/>        
            <Button Content=”change background” Width=”150″ Click=”Button_Click”></Button>
        </StackPanel>
    </Canvas>
</UserControl>

So, we have a listbox with an ItemTemplate with  a UserControl in it, by default we are going to get a StackPanel for the ItemsPanel.

we are going to bind the listbox to some data
 void Page_Loaded(object sender, RoutedEventArgs e)
        {
            List<ProductData> products = new List<ProductData>();
            for (int i = 0; i < 20; i++)
                products.Add(new ProductData { ProductID = i, Name = “Product..” + i.ToString() });

            list1.ItemsSource = products;
        }

The product class is defined like this

 public class ProductData
    {
        public int ProductID { get; set; }
        public string Name { get; set; }
    }

when we click the button we will change the background of the StackPanel which is in the UserControl(Product)

UserControl(Product) is defined like this

<UserControl x:Class=”SilverlightApplication1.Product”
    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” 
    >
    <StackPanel x:Name=”stackpanel1″ Orientation=”Horizontal”>
        <TextBlock Text=”{Binding ProductID}”></TextBlock>
        <TextBlock Margin=”10,2,2,2″ Text=”{Binding Name}”></TextBlock>
    </StackPanel>
</UserControl>

The Method to get the child of a given type from the VisualTree is below

public T GetChild<T>(DependencyObject obj) where T : DependencyObject
        {
            DependencyObject child = null;
            for (Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                child = VisualTreeHelper.GetChild(obj, i);
                if (child != null && child.GetType() == typeof(T))
                {
                    break;
                }
                else if (child != null)
                {
                    child = GetChild<T>(child);
                    if (child != null && child.GetType() == typeof(T))
                    {
                        break;
                    }
                }
            }
            return child as T;
        }
The Click event handler for the button is defined like this

 private void Button_Click(object sender, RoutedEventArgs e)
        {
            ListBoxItem lbi;           
            StackPanel sp = GetChild<StackPanel>(list1) as StackPanel;         
            for (int i = 0; i < sp.Children.Count; i++)
            {
                lbi = sp.Children[i] as ListBoxItem;
                Product p = GetChild<Product>(lbi);
                p.SetBGColor();
            }
        }

1. we are getting the 1st StackPanel in the VisualTree of the ListBox, this holds all the items of the listbox
2. As the content of the Datatemplate gets wrapped in a ListBoxItem as get that
3. finally we go to the actual Control, in our case the product using the helper function we wrote. once we get the control I am calling a method in that to change the Background color

you can download the code here

Advertisements

11 thoughts on “Getting the control inside a DataTemplate

  1. I’ve tried to use this example for CellTemplate.

    Im my case, the code is like that:

    DataGrid dg = new DataGrid();
    DataGridTemplateColumn dgtc = new DataGridTemplateColumn();

    dgtc.CellTemplate = myGetTemplateFromMyString();

    dg.Columns.Add(dgtc);

    myGetTemplateFromMyString() retunrs a very simple DataTemplate built from XAML-string and have a TextBlock only.

    Is it possible to get the TextBlock from dgtc.CellTemplate in this case ? There is no equivalent of ListBoxItem in DataGrid.

    B

  2. Of course, not. But I’ll try. Thanks.

    Ps.
    This subject really inspired me. I appreciate, that you wrote and share small but very helpful “GetChild” method. Thank you.

    B.

  3. I haven’t tested this exhaustively, but I think it works – just a simplified version of the GetChild function above.

    public T GetChild(DependencyObject obj) where T : DependencyObject
    {
    DependencyObject child = null;
    for( int i = 0; i < VisualTreeHelper.GetChildrenCount( obj ); i++ )
    {
    child = VisualTreeHelper.GetChild( obj, i );
    if( child != null && child.GetType() != typeof( T ) )
    {
    child = GetChild( child );
    }
    }
    return child as T;
    }

  4. Thank you so much. I downloaded the code. Things have changed a bit in the visual tree there, now that we are onVSE2012 and Silverlight5, but I got it to work, and the GetChild Function has made my app instantly come alive. It is an app like facebook, with posts, comments on the posts and then replies on the comments. This translates to an ItemsControl inside an ItemsControl inside a DataGrid. Was never going to work until I found your post. And suddenly it all sprang to life. So good!

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 )

Google+ photo

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

Connecting to %s