How to get the ListBoxItem for an item in ListBox

2019-02-27 12:36发布

问题:

I have a ListBox with Foo objects, and based on some events I disable/enable the ListBoxItems in the ListBox. Using the ListBox.Items property I find Foo objects, and from what I've understood I need to use the following function to get the ListBoxItem container for the Foo. Correct?

foreach (var item in Items)
{
    var lbi = ItemContainerGenerator.ContainerFromItem(foo) as ListBoxItem;
    // do something
}

Actually I have a custom control FilteringListBox which inherit ListBox and adds an extra property to it. The above code is in the code behind of the custom control and works just fine when the FilteringListBox is done being created. My problem however is that I try doing this when some property is bound. I have a property FilteringCollection and a PropertyCallback triggered when this is bound. In this callback I will store the FilteringCollection, but I will also do the initial filtering - running through the set collection and disable any ListBoxItem representing a Foo which is in the FilteringCollection.

This is where I get problems. I find all the Foos, so I verify that the ItemsSource is set, but doing the ItemContainerGenerator.ContainerFromItem I get null. It's like the ListBoxItems aren't created yet. Aren't they? Here is my binding:

<custom:FilteringListBox ItemsSource="{Binding AvailableFoos}" FilteringCollection="{Binding AlreadyIncludedFoos}"></custom:FilteringListBox>

So; either: How can I get the ListBoxItems on "bind-time"? Or - if I can't; is there some event I can override that tells me the ListBox is done creating ListBoxItems? Tried OnInitialized without luck...

回答1:

Actually a better solution seems to be using the ItemContainerGenerator. Hook up an event handler on creation:

ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;

And make the event handler do what needs to be done:

protected void ItemContainerGenerator_StatusChanged(object sender, System.EventArgs e)
{
    if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
        EvaluateInitialElements(); 
}


回答2:

The event OnRender is triggered when the component is ready to be rendered, and hence the ListBoxItem's are created. Doing the initial handling of the filtering on this event seems to ensure that everything I need is ready. I evaluate and disable elements, and then trigger the rendering:

protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
{
    EvaluateInitialElements();
    base.OnRender(drawingContext);
}