Home > Silverlight > Getting the control inside a DataTemplate

Getting the control inside a DataTemplate

September 24, 2008 lee Leave a comment Go to comments

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

Categories: Silverlight
  1. Bartlomiej
    October 24, 2008 at 2:46 pm | #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. lee
    October 25, 2008 at 8:38 am | #2

    Did you try using GetCellContent method?

  3. Bartlomiej
    October 25, 2008 at 3:41 pm | #3

    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.

  4. Steve
    April 12, 2009 at 3:25 am | #4

    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;
    }

    • lee
      April 12, 2009 at 8:05 am | #5

      Steve,
      Thanks for the code, it looks more clean

  5. Jim
    October 8, 2009 at 7:38 pm | #6

    Thanks for the ideas — Got me past a problem

    • lee
      October 8, 2009 at 7:47 pm | #7

      you are welcome. there are quite a few times, I refered to my own posts

  1. No trackbacks yet.