(X) Hide this
    • Login
    • Join
      • Say No Bots Generate New Image
        By clicking 'Register' you accept the terms of use .

Silverlight 2 - Getting to the ListBoxItems in a ListBox

(1 votes)
9 comments   /   aggregated from Mike Taulty's Blog on Apr 15, 2008   /   original article
Categories:   General

If you've got a Silverlight UI like this;

    <Grid x:Name="LayoutRoot" Background="White">
    <ListBox
      ItemsSource="{Binding}"
      x:Name="lstNumbers">
      <ListBox.ItemTemplate>
        <DataTemplate>
          <StackPanel
            Orientation="Horizontal">
            <Rectangle
              Width="100"
              Height="50"
              Fill="Red">Rectangle>
            <TextBlock
              Text="{Binding}" />
          StackPanel>
        DataTemplate>
      ListBox.ItemTemplate>
    ListBox>
  Grid>

and you set up the DataContext so that the binding works as in;

public partial class Page : UserControl
  {
    public Page()
    {
      InitializeComponent();
      this.Loaded += new RoutedEventHandler(Page_Loaded);
    }
    void Page_Loaded(object sender, RoutedEventArgs e)
    {
      this.DataContext = Enumerable.Range(1, 9);
    }
  }

then there might be circumstances where you want to get hold of some element of the UI for each item in the list like our ListBoxItem, StackPanel, Rectangle, TextBlock here.

You might write something like;

 void Page_Loaded(object sender, RoutedEventArgs e)
    {
      this.DataContext = Enumerable.Range(1, 9);

      lstNumbers.SelectionChanged += OnSelectionChanged;
    }
    void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
      foreach (object o in e.AddedItems)
      {
        // Do something
      } 
    }

but you'll find in your SelectionChanged handler that what you get access to are the data bound object values and not the UI elements (i.e. you get access to the integers here and not the ListBoxItem->StackPanel).

Generally, that's good because that's usually what you want but sometimes you might have a reason to actually get to the StackPanel or similar that we see above.

What to do?

One approach might be to derive your own ListBox. Maybe something a little like;

  public class MyListBox : ListBox
  {
    public MyListBox()
    {
      uiElements = new List();
    }
    public DependencyObject GetUIElementByItemIndex(int itemIndex)
    {
      return (uiElements[itemIndex]);
    }
    protected override DependencyObject GetContainerForItemOverride()
    {
      DependencyObject dObject = base.GetContainerForItemOverride();
      uiElements.Add(dObject);
      return (dObject);
    }
    List uiElements;
  }

 

and then I can use that in my UI and do something like;

 public partial class Page : UserControl
  {
    public Page()
    {
      InitializeComponent();
      this.Loaded += new RoutedEventHandler(Page_Loaded);
    }
    void Page_Loaded(object sender, RoutedEventArgs e)
    {
      this.DataContext = Enumerable.Range(1, 9);

      lstNumbers.SelectionChanged += OnSelectionChanged;
    }
    void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
      ListBoxItem lbi =
        (ListBoxItem)lstNumbers.GetUIElementByItemIndex(lstNumbers.SelectedIndex);

      lbi.Background = new SolidColorBrush(Colors.Green);
    }
  }

and that seems to work ok. Or, another approach that I used is to leave ListBox well alone and alter the UI definition and code to look something like this;

<Grid x:Name="LayoutRoot" Background="White">
    <ListBox
      ItemsSource="{Binding}"
      x:Name="lstNumbers">
      <ListBox.ItemTemplate>
        <DataTemplate>
          <StackPanel
            Orientation="Horizontal">
            <Rectangle
              Width="100"
              Height="50"
              Fill="Red">Rectangle>
            <TextBlock
              x:Name="myText"
              Text="{Binding}" 
              Loaded="OnTextBlockItemLoaded"/>
          StackPanel>
        DataTemplate>
      ListBox.ItemTemplate>
    ListBox>
  Grid>

That is, add a Loaded event on to some aspect of the UI. Then, in the handler for that event, grab the object you've created and store it for later use. For example;

 public partial class Page : UserControl
  {
    List textBlocks;

    public Page()
    {
      InitializeComponent();
      this.Loaded += new RoutedEventHandler(Page_Loaded);

      textBlocks = new List();
    }
    void Page_Loaded(object sender, RoutedEventArgs e)
    {
      this.DataContext = Enumerable.Range(1, 9);
    }
    void OnTextBlockItemLoaded(object sender, EventArgs args)
    {
      textBlocks.Add((TextBlock)sender);
    }
    void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
    }
  }

Subscribe

Comments

  • -_-

    RE: Silverlight 2 - Getting to the ListBoxItems in a ListBox


    posted by zacker on Aug 07, 2008 22:15

    Is there any working example for first approach?

  • -_-

    RE: Silverlight 2 - Getting to the ListBoxItems in a ListBox


    posted by Dmitry on Sep 08, 2009 22:34
    The second approach is so elegant! I just didn't realize I could use it. Thank you!
  • -_-

    RE: Silverlight 2 - Getting to the ListBoxItems in a ListBox


    posted by Dragan on Feb 16, 2010 18:25
    After hours of frustration trying to select the first item in the listbox that has a radio button defined in the datatemplate and selecting the radio button's IsChecked property to true, I found your example that solved my problem. So, almost 2 years after you wrote the article it helped me keep my sanity. Thank you very much!
  • -_-

    RE: Silverlight 2 - Getting to the ListBoxItems in a ListBox


    posted by Rui Craveiro on Feb 17, 2010 20:39
    Thank you, thank you, thank you!!!!
  • -_-

    RE: Silverlight 2 - Getting to the ListBoxItems in a ListBox


    posted by JoeBob on Mar 16, 2010 19:21
    ListBox.GetItemsHost().Children  will give you a collection of child elements int he items host control
  • -_-

    RE: Silverlight 2 - Getting to the ListBoxItems in a ListBox


    posted by Ciprian on Mar 18, 2010 21:41

    Your solution really helped me get going, at one point. Thanks for that. I've been using for some time no, but recently, I've run into a bit of a trouble and found out that the uiElements list was not in sync with the actual list of  ListBoxItems inside my ListBox. I started writting code to fix that, but I found myself elaborating too much logic to acomplish my goal. So, decided to do more digging.

    Oh, I must mention that I am using Silverlight 3, so not sure that SL2 supports the following.

    What I've found is that the ListBox class has a public property called ItemContainerGenerator and that by using it, one may actually get to the ListBoxItems within it. A few examples are:

    - get the item at some index:  ListBoxItem lbi1 = (ListBoxItem)(listBox.ItemContainerGenerator.ContainerFromIndex(0));

    - get the item based on the DataContext behind it:  ListBoxItem lbi2 = (ListBoxItem)(listBox.ItemContainerGenerator.ContainerFromItem(listBox.Items.CurrentItem));

    Hope this helps.

  • -_-

    RE: Silverlight 2 - Getting to the ListBoxItems in a ListBox


    posted by Ciprian on Mar 18, 2010 21:42

    Your solution really helped me get going, at one point. Thanks for that. I've been using for some time no, but recently, I've run into a bit of a trouble and found out that the uiElements list was not in sync with the actual list of  ListBoxItems inside my ListBox. I started writting code to fix that, but I found myself elaborating too much logic to acomplish my goal. So, decided to do more digging.

    Oh, I must mention that I am using Silverlight 3, so not sure that SL2 supports the following.

    What I've found is that the ListBox class has a public property called ItemContainerGenerator and that by using it, one may actually get to the ListBoxItems within it. A few examples are:

    - get the item at some index:  ListBoxItem lbi1 = (ListBoxItem)(listBox.ItemContainerGenerator.ContainerFromIndex(0));

    - get the item based on the DataContext behind it:  ListBoxItem lbi2 = (ListBoxItem)(listBox.ItemContainerGenerator.ContainerFromItem(listBox.Items.CurrentItem));

    Hope this helps.

  • -_-

    RE: Silverlight 2 - Getting to the ListBoxItems in a ListBox


    posted by Abubakar on Sep 07, 2010 13:13

    Hi,

    I need my controls inside ListBoxItem, Using the first approach it always return ListBoxItem object. That Also can be found using ListBox.ItemContainerGenerator.ContainerFromItem Method.

    any helps ?

  • -_-

    RE: Silverlight 2 - Getting to the ListBoxItems in a ListBox


    posted by Jake on Feb 23, 2011 20:41

    Thanks for your example....it was really helpful!

Add Comment

Login to comment:
  *      *