2013-11-02 34 views
0

我試圖做出一個行爲適用於選擇器繼承人(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時是0SelectedIndex-1

我需要一個事件和狀態的組合,這將清楚地表明一個ListView已準備好與它一起操作,準備滾動到所選元素並將其聚焦。

在此先感謝

回答

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