我正在尝试将行为应用于选择器继承者(ListView、ListBox 等),这将恢复所选元素并将其重点放在应用程序启动上。我还想在选项卡之间切换时聚焦选定的元素。
主要问题是找到 ListView 填充列表、完成所有内部活动并准备集中注意力的时间点。
我省略了关心 SelectedIndex 与持久性系统和清理代码的同步的行为部分,只显示了与控件交互的部分。
public class PersistSelectedItemIndexBehavior : Behavior<Selector>
{
protected override void OnAttached()
{
base.OnAttached();
RestorePersistedSelectedIndex();
AssociatedObject.Loaded += AssociatedObject_OnLoaded;
}
private void AssociatedObject_OnLoaded(object sender, RoutedEventArgs e)
{
AssociatedObject.GotFocus += AssociatedObject_OnGotFocus;
Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
{
AssosiatedObject.Focus();
ScrollSelectedItemIntoView(
AssociatedObject.FindVisualChild<ScrollViewer>());
}));
}
private void AssociatedObject_OnGotFocus(object _, RoutedEventArgs __)
{
// do it only once on loading control
AssociatedObject.GotFocus -= AssociatedObject_OnGotFocus;
Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(
SetFocusOnSelectedElement));
}
private void SetFocusOnSelectedElement()
{
var element = AssociatedObject.ItemContainerGenerator.ContainerFromItem(
AssociatedObject.SelectedItem) as IInputElement;
if (element != null)
element.Focus();
}
private void ScrollSelectedItemIntoView(ScrollViewer scrollViewer)
{
double position = AssociatedObject.SelectedIndex;
position -= scrollViewer.ViewportHeight / 2 - 1;
scrollViewer.ScrollToVerticalOffset(position);
}
}
当 ListView 中有几个项目时它可以工作,但如果有几百个项目,它就不会。何时ScrollSelectedItemIntoView
调用Items.Count
is0
和SelectedIndex
is -1
。
我需要一个事件和状态的组合,这将清楚地表明 ListView 已准备好对其进行操作,已准备好滚动到所选元素并将其聚焦。
提前致谢