我的View中有一个ItemsControl,它绑定到ViewModel的ObservableCollection。该集合已填满,之后会引发从VM到视图的事件(想想搜索结果和SearchFinished事件)。
我想将键盘焦点移动到ItemsControl中的第一个项目,但是当我在处理SearchFinished时在View的代码隐藏中执行它时,项目尚未呈现(集合已经填充,但是wpf的呈现是异步的)并且还没有发生),所以没有什么可以聚焦(Focus()需要已经构建了项目的可视树)。
我想(myItemsControl.ItemContainerGenerator.ContainerFromIndex(0)作为UIElement).Focus();,但由于第0项尚未加载,ContainerFromIndex(0)返回null。
我尝试使用低优先级的Dispatcher.BeginInvoke延迟它,但这取决于确切的时间并且通常不起作用。
如何等待ItemsControl中的第一项加载?
答案 0 :(得分:8)
您可以使用ItemContainerGenerator.StatusChanged
事件,然后检查其Status
属性。如果是Status == GeneratorStatus.ContainersGenerated
,那么您可以安全地获得第一个容器。
答案 1 :(得分:0)
在我的应用中,我发现 ItemContainerGenerator.StatusChanged
和 Status == GeneratorStatus.ContainersGenerated
与屏幕明显呈现的时刻不一致。实际上,在渲染大量项目时会出现相当大的延迟;此延迟发生在 ContainersGenerated
报告之后。
相反,我发现等待 ItemsPresenter.Loaded
事件效果更好。此事件似乎与渲染完成以及 UI 的非忙碌状态更接近。
由于 ItemsPresenter
是 ListBox
(或通常的 ItemsControl
)的控制模板的一部分,您可能必须重新定义该模板才能获得它。就我而言,无论如何我都有一个自定义模板,所以效果很好。
特别是在我的情况下,我使用的是 MultiSelector
,但就我所知,这个问题与 ItemsControl
或 ListBox
没有什么不同:< /p>
<MultiSelector
ItemsSource="{Binding ...}"
>
<MultiSelector.Template>
<ControlTemplate TargetType="{x:Type MultiSelector}">
<ScrollViewer>
<ItemsPresenter Loaded="ItemsPresenter_Loaded"/>
</ScrollViewer>
</ControlTemplate>
</MultiSelector.Template>
...
或者,您可能可以搜索可视化树以找到 ItemsPresenter。