在应用运行会话之间保留所选项目

时间:2013-11-02 11:08:04

标签: listview listbox wpf-controls

我正在尝试将行为应用于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中有一些项目时,它会起作用,但如果有几百个项目则不行。调用ScrollSelectedItemIntoViewItems.Count0SelectedIndex-1

我需要事件和状态的组合,这些事件和状态将清楚地表明ListView已准备好与它一起操作,准备好滚动到所选元素并将其聚焦。

提前致谢

1 个答案:

答案 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));
  }
}