1

I am unable to get ListBoxItem from ListBox. I have created ListBox dynamically; it is not in XAML. I just set ItemsSource and I have values in all the items but cannot access/convert each item as ListBoxItem.

 for (int i = 0; i < listBox.Items.Count; i++)
            {
                ListBoxItem item = (ListBoxItem)listBox.ItemContainerGenerator.ContainerFromItem(listBox.Items[i]);
                // item is null after above statement
            }

Note: I just checked 'listBox.ItemContainerGenerator.Status' . listBox.ItemContainerGenerator.Status is 'notStarted'.

What to do now?

Ahsan
  • 648
  • 1
  • 10
  • 27

2 Answers2

2

It sounds like you are not giving WPF enough time to render the <ListBoxItem> objects before calling your method.

A common way of accessing the ListBoxItems right after its Items property is set is to use the ItemContainerGenerator.StatusChanged event, like this:

void MyConstructor()
{
    listBox.ItemsSource = someCollection;

    listBox.ItemContainerGenerator.StatusChanged += 
        ItemContainerGenerator_StatusChanged;
}

void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
    // If containers have been generated
    if (listBox.ItemContainerGenerator.Status == 
        System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
    {
        // Remove event
        listBox.ItemContainerGenerator.StatusChanged -= 
            ItemContainerGenerator_StatusChanged;

        // Do whatever here
        foreach(var item in listBox.Items)
        {
            var item = (ListBoxItem)listBox.ItemContainerGenerator.ContainerFromItem(item);
            // do whatever you want with the item
        }

    }
}

WPF runs code at different DispatcherPriorities. Code run in the constructor or on load is run at Normal priority, while the generation of ListBoxItem objects doesn't occur until Render priority, which runs after all Normal priority items have finished running.

You could alternatively use the Dispatcher to run your code at a later dispatcher priority than Render as well.

Rachel
  • 130,264
  • 66
  • 304
  • 490
  • 1
    But what if it's virtualized? It hasn't realized every listbox item :D – 123 456 789 0 May 06 '14 at 17:40
  • I just checked 'listBox.ItemContainerGenerator.Status' . listBox.ItemContainerGenerator.Status is 'notstarted' – Ahsan May 06 '14 at 17:41
  • 1
    @Ahsan Yes, if you want you can write the `ItemContainerGenerator.Status` to the Debug window in the `StatusChanged` event, and you will see the order of events that the `ItemContainerGenerator` goes through. – Rachel May 06 '14 at 17:42
  • Can you please simply tell me how to generate/start 'listBox.ItemContainerGenerator'? – Ahsan May 06 '14 at 17:45
  • @lll:Yes it is virtuallized as listbox does not exist physically in XAML. It is just in code. Can youplease simply tell me how to generate/start 'listBox.ItemContainerGenerator'? – Ahsan May 06 '14 at 17:52
  • 1
    @Ahsan It starts automatically when WPF tries to render the items contained in `ListBox.Items`. If you're having problems with this, perhaps you can edit your question to share the code you're using to create and populate your ListBox? – Rachel May 06 '14 at 17:55
  • @Ill If its virtualized, then you really shouldn't be referencing the `` object anyways since a virtualized container won't create a `` for every object, and forcing it to do something like this would probably be very bad for performance :) – Rachel May 06 '14 at 18:01
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/52127/discussion-between-ahsan-and-rachel) – Ahsan May 06 '14 at 18:10
  • @Rachel What if I have 1,000,000 items and there is a requirement that when it loads it should scroll to 900,000,000 and I have to modify the a dependency property to it? – 123 456 789 0 May 06 '14 at 19:17
  • @Ill Well for one, there wouldn't be a 900,000,000th item in a set of 1,000,000 items :) But I'm fairly sure you can set a scroll position without looping through every single item (I want to say it's `.ScrollIntoView(item)`, but I'm not positive). If you want to set a DP on that specific item, it should be set on the data object this list is bound to and the property bound to the UI. You should not be accessing the UI component for the object to set that property, as it can't be guartenteed that the data object displayed in that UI object will be the same at all times with virtualization – Rachel May 06 '14 at 19:22
-2

Why are you casting the listbox to a listboxitem?

Here is a simular question about getting the selected items listbox selected items in winform

You should be able to get the item by it's index

ListBox1.Items.Item(index)
Community
  • 1
  • 1
ChampChris
  • 1,565
  • 5
  • 26
  • 44
  • 1
    WPF does not work the same way as Winforms. The items stored in `.Items` is not a list of `ListBoxItem` objects, but is instead a list of data objects – Rachel May 06 '14 at 17:43