我正在尝试将行为应用于Selector继承者(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
为0
而SelectedIndex
为-1
。
我需要事件和状态的组合,这些事件和状态将清楚地表明ListView已准备好与它一起操作,准备好滚动到所选元素并将其聚焦。
提前致谢
答案 0 :(得分:0)
最后我解决了一个问题。
public class PersistSelectedItemIndexBehavior : Behavior<Selector>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Loaded += AssociatedObject_OnLoaded;
DependencyPropertyDescriptor.FromProperty(Selector.SelectedIndexProperty, AssociatedObject.GetType())
.AddValueChanged(AssociatedObject, OnSelectedIndexChanged);
RestorePersistedSelectedIndex();
}
private void OnSelectedIndexChanged(object sender, EventArgs e)
{
DependencyPropertyDescriptor.FromProperty(Selector.SelectedIndexProperty, AssociatedObject.GetType())
.RemoveValueChanged(AssociatedObject, OnSelectedIndexChanged);
Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
ScrollSelectedItemIntoView(AssociatedObject.FindVisualChild<ScrollViewer>())));
}
private void AssociatedObject_OnLoaded(object sender, RoutedEventArgs e)
{
AssociatedObject.GotFocus += AssociatedObject_OnGotFocus;
}
private void AssociatedObject_OnGotFocus(object sender, RoutedEventArgs routedEventArgs)
{
AssociatedObject.GotFocus -= AssociatedObject_OnGotFocus;
Dispatcher.BeginInvoke(DispatcherPriority.Input, (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);
Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(SetFocusOnSelectedElement));
}
}