Прокрутите новый элемент в ItemsControl в поле зрения

У меня есть ItemsControl, привязанный к ObservableCollection. У меня есть этот метод в коде, который добавляет новую модель в список. Затем я хотел бы прокрутить новый элемент (внизу списка) в поле зрения.

Я думаю, что размер ItemsControl еще не обновлен, когда я запрашиваю размер, поскольку ActualHeight до и после добавления модели одинаковы. Действие этого кода заключается в прокрутке до точки чуть выше нового элемента.

Откуда мне знать, каким будет новый ActualHeight?

Вот мой код:

        ViewModel.CreateNewChapter();
        var height = DocumentElements.ActualHeight;
        var width = DocumentElements.ActualWidth;
        DocumentElements.BringIntoView(new Rect(0, height - 1, width, 1));

person Pieter Breed    schedule 23.10.2009    source источник


Ответы (1)


Я думаю, вам нужно вызвать BringIntoView для контейнера элементов, а не для самого ItemsControl:

var container = DocumentElements.ItemContainerGenerator.ContainerFromItem(model) as FrameworkElement;
if (container != null)
    container.BringIntoView();

РЕДАКТИРОВАТЬ: на самом деле это не работает, потому что на данный момент контейнер элемента еще не создан... Возможно, вы могли бы обработать событие StatusChanged для ItemContainerGenerator. Я попробовал следующий код:

public static class ItemsControlExtensions
{
    public static void BringItemIntoView(this ItemsControl itemsControl, object item)
    {
        var generator = itemsControl.ItemContainerGenerator;

        if (!TryBringContainerIntoView(generator, item))
        {
            EventHandler handler = null;
            handler = (sender, e) =>
            {
                switch (generator.Status)
                {
                    case GeneratorStatus.ContainersGenerated:
                        TryBringContainerIntoView(generator, item);
                        break;
                    case GeneratorStatus.Error:
                        generator.StatusChanged -= handler;
                        break;
                    case GeneratorStatus.GeneratingContainers:
                        return;
                    case GeneratorStatus.NotStarted:
                        return;
                    default:
                        break;
                }
            };

            generator.StatusChanged += handler;
        }
    }

    private static bool TryBringContainerIntoView(ItemContainerGenerator generator, object item)
    {
        var container = generator.ContainerFromItem(item) as FrameworkElement;
        if (container != null)
        {
            container.BringIntoView();
            return true;
        }
        return false;
    }
}

Однако это тоже не работает... по какой-то причине ContainerFromItem по-прежнему возвращает значение null после изменения статуса на ContainersGenerated, и я понятия не имею, почему: S


РЕДАКТИРОВАТЬ: ОК, теперь я понимаю... это было из-за виртуализации: контейнеры генерируются только тогда, когда их нужно отображать, поэтому контейнеры для скрытых элементов не генерируются. Если вы отключите виртуализацию для ItemsControl (VirtualizingStackPanel.IsVirtualizing="False"), приведенное выше решение работает нормально.

person Thomas Levesque    schedule 23.10.2009
comment
DocumentElements.ItemContainerGenerator.ContainerFromItem (модель) возвращает значение null? Я не думаю, что представление еще не обновлено до нового элемента в источнике данных. - person Pieter Breed; 24.10.2009
comment
ах, да, я забыл об этом ... но в любом случае, если контейнер еще не находится в ItemsControl, вы не можете перейти к нему: S - person Thomas Levesque; 24.10.2009
comment
Я пытался сделать это, но это не удалось. Событие для ContainersGenerated не запускается в генераторе. - person Pieter Breed; 24.10.2009