ListBox ScrollIntoView when using CollectionViewSource with GroupDescriptions (i.e. IsGrouping == True)

前端 未结 2 1042
太阳男子
太阳男子 2021-02-08 07:43

Short version

I would like to scroll the ListBox item into view when the selection is changed.

Long version

2条回答
  •  栀梦
    栀梦 (楼主)
    2021-02-08 07:53

    I have found a solution to my problem. I was certain that I wasn't the first person to hit this issue so I continued to search StackOverflow for solutions and I stumbled upon this answer by David about how ItemContainerGenerator works with a grouped list.

    David's solution was to delay accessing the ItemContainerGenerator until after the rendering process.

    I have implemented this solution, with a few changes that I will detail after.

    private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        ListBox control = (ListBox)sender;
    
        if (control.IsGrouping)
        {
             if (control.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
                  Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(DelayedBringIntoView));
             else
                  control.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
        }
        else
            control.ScrollIntoView(control.SelectedItem);
    }
    
    private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
    {
        if (ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
            return;
    
        ItemContainerGenerator.StatusChanged -= ItemContainerGenerator_StatusChanged;
        Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(DelayedBringIntoView));
    }
    
    private void DelayedBringIntoView()
    {
        var item = ItemContainerGenerator.ContainerFromItem(SelectedItem) as ListBoxItem;
        if (item != null)
            item.BringIntoView();
    }
    

    Changes:

    • Only uses the ItemContainerGenerator approach when it IsGrouping is true, otherwise continue to use the default ScrollIntoView.
    • Check if the ItemContainerGenerator is ready, if so dispatch the action, otherwise listen for the ItemContainerGenerator status to change.. This is important as if it is ready then the StatusChanged event will never fire.

提交回复
热议问题