WPF ItemsControl - как узнать, когда элементы завершили загрузку, чтобы я мог сфокусироваться на первом?

У меня есть ItemsControl в моем представлении, который привязан к ObservableCollection из ViewModel. Коллекция заполняется, а затем возникает событие от виртуальной машины для просмотра (подумайте о результатах поиска и событии SearchFinished).

Я хотел бы переместить фокус клавиатуры на первый элемент в ItemsControl, но когда я делаю это в коде программной части представления при обработке SearchFinished, элементы еще не отображаются (коллекция уже заполнена, но визуализация wpf асинхронна и не выполняется) пока не произошло), поэтому фокусироваться не на чем (Focus () должен иметь уже построенное визуальное дерево элементов).

Я хотел сделать (myItemsControl.ItemContainerGenerator.ContainerFromIndex (0) as UIElement) .Focus ();, но поскольку 0-й элемент еще не загружен, ContainerFromIndex (0) возвращает null.

Я попытался отложить его с помощью Dispatcher.BeginInvoke ... с низким приоритетом, но это зависит от точного времени и обычно не работает.

Как мне дождаться загрузки первого элемента ItemsControl?


person Tomáš Kafka    schedule 22.03.2010    source источник


Ответы (2)


Вы можете использовать событие ItemContainerGenerator.StatusChanged, а затем проверить его свойство Status. Если Status == GeneratorStatus.ContainersGenerated, то можете смело получать первую тару.

person Abe Heidebrecht    schedule 22.03.2010

В своем приложении я обнаружил, что ItemContainerGenerator.StatusChanged с Status == GeneratorStatus.ContainersGenerated не совпадают с моментом визуализации экрана. Фактически произошла значительная задержка при визуализации большого # элементов; эта задержка произошла после сообщения ContainersGenerated.

Вместо этого я обнаружил, что ожидание события ItemsPresenter.Loaded работает лучше. Это событие, похоже, гораздо больше совпадает с завершением рендеринга, а также с незанятым статусом пользовательского интерфейса.

Поскольку ItemsPresenter является частью шаблона управления ListBox (или ItemsControl в целом), вам, возможно, придется переопределить этот шаблон, чтобы получить его. В моем случае у меня все равно был собственный шаблон, так что он работал хорошо.

В частности, в моем случае так получилось, что я использовал MultiSelector, но для целей этого вопроса он ничем не отличается от ItemsControl или ListBox, насколько мне известно:

<MultiSelector
   ItemsSource="{Binding ...}"
   >

   <MultiSelector.Template>
      <ControlTemplate TargetType="{x:Type MultiSelector}">
        <ScrollViewer>
            <ItemsPresenter Loaded="ItemsPresenter_Loaded"/>
        </ScrollViewer>
    </ControlTemplate>
</MultiSelector.Template>

...

В качестве альтернативы вы, вероятно, можете выполнить поиск в визуальном дереве, чтобы найти ItemsPresenter.

person StayOnTarget    schedule 08.03.2021