Click here to Skip to main content
15,881,588 members
Articles / Programming Languages / C#

UserControl populating ItemsControl – Manipulation of ItemsControl collection from inner UserControl

Rate me:
Please Sign up or sign in to vote.
3.33/5 (4 votes)
23 May 2012CPOL2 min read 16.9K   3   2
UserControl populating ItemsControl – manipulation of ItemsControl collection from inner UserControl.

Introduction

I had a problem: on a certain Silverlight page, I needed to un-expand all the Expanders except for the Expander that the user selects to expand. Googled around and couldn’t get a solution so I had to dig in on it and get it to work.

This is what I came up with and I think it’s good enough to share. I just apologize for the naming of namespaces, classes, methods, and variables for they use my own language (most of the time!). The content of the UserControl and data are very specific to every project so I’ll show only the needed information for clarity purposes.

Background 

The general solution is a Parent control, a ScrollViewer, holding a StackPanel. In it the ItemsControl with its ItemTemplate being of a UserControl type bound to the ItemsControl.ItemsSource. Whenever a user expands one of the child Expanders, the child UserControl fires an event that is picked up by the Parent and then processes whatever is to be done on the children collection. The problem is that the StackPanel’s children collection is an ItemsControl and I needed to get to the Expanders in it. 

Using the code - passing the event to parent control

The UserControl - myTema 

The UserControl myTema is basically an Expander with some stuff in it that consumes the bound data (in my case, it's a HeaderTemplate and a bunch of nested UserControls not needed for this explanation) and an action to the Expanded event: 

XML
<Grid x:Name="LayoutRoot" >
  <toolkit:Expander x:Name="ExpanderTema" Expanded="ExpanderTema_Expanded" 
            HeaderTemplate="{StaticResource ExpanderTemaDataTemplate}" 
            Header="{Binding myTema_Conteudo, ElementName=myTemaRoot}" >
    <StackPanel x:Name="stackSugest" >
      <!-- Controls that hold the data -->
    </StackPanel>
  </toolkit:Expander>
</Grid>
C#
public event EventHandler ExpanderTemaExpanded;

private void ExpanderTema_Expanded(object sender, System.Windows.RoutedEventArgs e)
{
    ExpanderTemaExpanded(sender, null);
}

The ParentControl

The StackPanel parent control has its ItemsControl.ItemsSource based on a local variable and catches the ExpanderTemaExpanded event of any of its UserControl children. 

C#
List<myTema_Info> ListTema = new List<myTema_Info>();
itemsMyTemas.ItemsSource = ListTema; 
XML
<ScrollViewer x:Name="ScrollViewer1" >
  <Grid>
    <StackPanel x:Name="stackMyTemas" >
      <ItemsControl x:Name="itemsMyTemas" >
        <ItemsControl.ItemTemplate>
          <DataTemplate>
            <componente:myTema x:Name="myCategory_Temas" 
                ExpanderTemaExpanded="myCategory_Temas_ExpanderTemaExpanded" 
                myTema_Conteudo="{Binding}" />
          </DataTemplate>
        </ItemsControl.ItemTemplate>
      </ItemsControl>
    </StackPanel>
  </Grid>
</ScrollViewer>

In the method called by the USerControl, the ExpanderTemaExpanded event is where the magic happens with the GetAllChildFrameworkElement function explained in the next section.

C#
private void myCategory_Temas_ExpanderTemaExpanded(object sender, System.EventArgs e) 
{ 
  var found = Tools.GetAllChildFrameworkElement(stackMyTemas, typeof(Expander));
  foreach (Expander item in found)
  {
    if (item != (Expander)sender) // If item is different from the one that originated the call 
      item.IsExpanded = false; // Do something to it (my case, unexpand) 
  }
} 

Using the code - the generic static class 

In my case I use a generic

static
class where I put all generic functions like the ones needed to find all the
Expander
s on the parent StackPanel children's collection.

C#
public static class Tools
{
  public static List<FrameworkElement> GetAllChildFrameworkElement(
         FrameworkElement parentElement, Type typeRequired)
  {
     List<FrameworkElement> childFrameworkElementFound = 
                                  new List<FrameworkElement>();
     SearchAllChildFrameworkElement(parentElement, childFrameworkElementFound, typeRequired);
     return childFrameworkElementFound;
  }

  private static void SearchAllChildFrameworkElement(FrameworkElement parentFrameworkElement, 
          List<FrameworkElement> allChildFrameworkElement, Type typeRequired)
  {
    int childrenCount = VisualTreeHelper.GetChildrenCount(parentFrameworkElement);
    if (childrenCount > 0)
    {
      for (int i = 0; i < childrenCount; i++)
      {
        FrameworkElement childFrameworkElement = 
           (FrameworkElement)VisualTreeHelper.GetChild(parentFrameworkElement, i);
        if (childFrameworkElement.GetType().Equals(typeRequired))
        {
          allChildFrameworkElement.Add(childFrameworkElement);
        }

        SearchAllChildFrameworkElement(childFrameworkElement, 
                  allChildFrameworkElement, typeRequired);
      }
    }
  }
}

This particular piece of code I found in http://forums.silverlight.net/t/160356.aspx.

It uses the VisualTreeHelper class and a recursive method to loop through the children collection looking for the ones with a matching type to the type we are looking for.

It returns a collection of them all, if any, and on that collection, you can do whatever you want or need to do.

Hope it helps someone.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer
Portugal Portugal
Database and Silverlight applications designer and developer.

Comments and Discussions

 
GeneralMy vote of 1 Pin
Agon Avdimetaj23-May-12 9:43
Agon Avdimetaj23-May-12 9:43 
GeneralRe: My vote of 1 Pin
Jorge J. Martins24-May-12 6:32
professionalJorge J. Martins24-May-12 6:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.