Search code examples
wpflistboxitemscontrollistboxitem

ItemContainerGenerator.ContainerFromItem method returns null if item has grouped


In WPF ListBox, I can get the selected item container using the method ItemContainerGenerator.ContainerFromItem(selectedItem) but it is not working when ListBoxItem is grouped.

MainWindow.xaml

<ListBox x:Name="listBox" ItemsSource="{Binding Contacts}" Loaded="cardView1_Loaded" SelectedIndex="0" Width="250" Height="250"
             HorizontalAlignment="Center" VerticalAlignment="Center">
        <ListBox.GroupStyle>
            <GroupStyle/>
        </ListBox.GroupStyle>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Name}"/>
                    <TextBlock Text="{Binding Age}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

MainWindow.xaml.cs

In the loaded method, First I have called this method ItemContainerGenerator.ContainerFromItem(selectedItem) and it returns the container of the selected item because the Listbox item is not grouped. Then I have added grouping for Listbox item. Now, if i called this method it returns null.

 public MainWindow()
    {
        InitializeComponent();

        DataContext = new ViewModel();
    }

    private void cardView1_Loaded(object sender, RoutedEventArgs e)
    {
        withOutGroup.Text = withOutGroup.Text + listBox.ItemContainerGenerator.ContainerFromItem(listBox.SelectedItem);
        ICollectionView collectionView = CollectionViewSource.GetDefaultView(listBox.ItemsSource);
        collectionView.GroupDescriptions.Add(new PropertyGroupDescription("Name"));
        withGroup.Text = withGroup.Text + listBox.ItemContainerGenerator.ContainerFromItem(listBox.SelectedItem);
    }

enter image description here

Sample: ListBox-Testing-Project

How can I get the selected item container if the Listbox item is grouped?


Solution

  • You need to wait to call the ContainerFromItem method until the container has actually been created. This works:

    private void cardView1_Loaded(object sender, RoutedEventArgs e)
    {
        ICollectionView collectionView = CollectionViewSource.GetDefaultView(listBox.ItemsSource);
        collectionView.GroupDescriptions.Add(new PropertyGroupDescription("Name"));
    
        Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Loaded,
            new Action(() =>
            {
                var container = listBox.ItemContainerGenerator.ContainerFromItem(listBox.SelectedItem);
                //...
            }));
    }