private static void SelectContainerFromItem()

in src/StructuredLogViewer/Controls/TreeViewExtensions.cs [85:192]


        private static void SelectContainerFromItem<T>(this ItemsControl container, SelectInfo<T> selectInfo, TreeView treeView)
        {
            var currentItem = selectInfo.Items.First();
            var itemContainerGenerator = container.ItemContainerGenerator;

            if (itemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
            {
                // If the item containers haven't been generated yet, attach an event
                // and wait for the status to change.
                EventHandler selectWhenReadyMethod = null;

                selectWhenReadyMethod = (ds, de) =>
                {
                    if (itemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
                    {
                        // Stop listening for status changes on this container
                        itemContainerGenerator.StatusChanged -= selectWhenReadyMethod;

                        // Attempt to fix https://github.com/KirillOsenkov/MSBuildStructuredLog/issues/453
                        container.Dispatcher.BeginInvoke((Action)delegate
                        {
                            // Search the container for the item chain
                            SelectContainerFromItem(container, selectInfo, treeView);
                        }, DispatcherPriority.Render);
                    }
                };

                itemContainerGenerator.StatusChanged += selectWhenReadyMethod;

                return;
            }

            Debug.Assert(itemContainerGenerator.Status == GeneratorStatus.ContainersGenerated);

            // Compare each item in the container and look for the next item
            // in the chain.
            foreach (object item in container.Items)
            {
                var convertedItem = (T)item;

                // Compare the converted item with the item in the chain
                if ((selectInfo.CompareMethod != null) && selectInfo.CompareMethod(convertedItem, currentItem))
                {
                    // Since the TreeViewItems are in a virtualized panel, the item to be selected may not be realized,
                    // need to ensure it is brought into view, so it can be selected.
                    ItemsPresenter itemsPresenter = FindVisualChild<ItemsPresenter>(container);
                    var containerFromItem = itemContainerGenerator.ContainerFromItem(item) as FrameworkElement;
                    if (itemsPresenter != null && (containerFromItem == null || !containerFromItem.IsOnScreen(treeView)))
                    {
                        int index = container.Items.IndexOf(currentItem);

                        var child = VisualTreeHelper.GetChild(itemsPresenter, 0);
                        var virtualizingPanel = child as VirtualizingStackPanel;
                        if (virtualizingPanel != null)
                        {
                            virtualizingPanel.BringIndexIntoViewPublic(index);
                        }
                        else
                        {
                            if (child is StackPanel stackPanel)
                            {
                                if (stackPanel.Children[index] is FrameworkElement frameworkElement)
                                {
                                    frameworkElement.BringIntoView();
                                }
                            }
                        }
                    }

                    var containerParent = (ItemsControl)itemContainerGenerator.ContainerFromItem(item);
                    if (containerParent == null)
                    {
                        return;
                    }

                    // Replace with the remaining items in the chain
                    selectInfo.Items = selectInfo.Items.Skip(1);

                    // If no items are left in the chain, then we're finished
                    if (selectInfo.Items.Count() == 0)
                    {
                        // Select the last item
                        if (selectInfo.SelectItem != null)
                        {
                            Action action = new Action(() =>
                            {
                                selectInfo.SelectItem(containerParent, selectInfo);
                            });

                            // Here we dispatch the select action so the TreeViewItem is focused
                            // and scrolled into view correctly.
                            container.Dispatcher.BeginInvoke(action, DispatcherPriority.Render);
                        }
                    }
                    else
                    {
                        // Request more items and continue the search
                        if (selectInfo.NeedMoreItems != null)
                        {
                            selectInfo.NeedMoreItems(containerParent, selectInfo);
                            SelectContainerFromItem(containerParent, selectInfo, treeView);
                        }
                    }

                    break;
                }
            }
        }