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
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
Did you try using GetCellContent method?
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.
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;
}
Steve,
Thanks for the code, it looks more clean
This function won’t work. Lee’s function work. The functions misses to call the GetChild method properly
Thanks for the ideas — Got me past a problem
you are welcome. there are quite a few times, I refered to my own posts
Thanks MUCH!!! Your function save my day!
Great GetChild() function! Thank you for sharing.
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!