I have a wpf user management project configured similarly (for the most part) to WPF applications with the Design-ViewModel Design Model template . Basically, I have a content control that contains a tab control. The first tab contains the search results, and any additional tabs are opened by clicking on an element from the search results to see a more detailed representation of the element.
My main problem is that I reuse the search results tab anytime when someone enters search criteria and runs a search command. Scrolling scrolling does not scroll up when the collection of search results is re-populated (if the user scrolls down the list).
Initially, I re-populated the collection of search results so that the CollectionChanged event occurred. Then I looked through the attached property to allow scrolling up, and it seemed that replacing the entire collection was the way to go (since ItemsControl does not implement the ICollectionNotifyChanged interface).
So, I made a change, and everything was fine. Starting a new search replaced the collection of search result elements, which activated the attached property and scrolled the list to the top. However, I now have a problem that when I switch to another tab to view the detailed view of the item, it launches the attached property and scrolls the search results in the first tab at the top . I am not sure how to solve this situation.
public static class ScrollToTopBehavior { public static readonly DependencyProperty ScrollToTopProperty = DependencyProperty.RegisterAttached ( "ScrollToTop", typeof (bool), typeof (ScrollToTopBehavior), new UIPropertyMetadata(false, OnScrollToTopPropertyChanged) ); public static bool GetScrollToTop(DependencyObject obj) { return (bool) obj.GetValue(ScrollToTopProperty); } public static void SetScrollToTop(DependencyObject obj, bool value) { obj.SetValue(ScrollToTopProperty, value); } private static void OnScrollToTopPropertyChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs e) { var itemsControl = dpo as ItemsControl; if (itemsControl == null) return; DependencyPropertyDescriptor dependencyPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, typeof (ItemsControl)); if (dependencyPropertyDescriptor == null) return; if ((bool) e.NewValue) { dependencyPropertyDescriptor.AddValueChanged(itemsControl, ItemsSourceChanged); } else { dependencyPropertyDescriptor.RemoveValueChanged(itemsControl, ItemsSourceChanged); } } private static void ItemsSourceChanged(object sender, EventArgs e) { var itemsControl = sender as ItemsControl; EventHandler eventHandler = null; eventHandler = delegate { if (itemsControl != null && itemsControl.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) { var scrollViewer = VisualTreeHelpers.FindChild<ScrollViewer>(itemsControl); scrollViewer.ScrollToTop(); itemsControl.ItemContainerGenerator.StatusChanged -= eventHandler; } }; if (itemsControl != null) itemsControl.ItemContainerGenerator.StatusChanged += eventHandler; } }
I bound this property to a user search result control like this:
<ListView ...some properties left out for brevity... DataContext="{StaticResource SearchResultsViewSource}" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding}" SelectionMode="Single" behaviours:ScrollToTopBehavior.ScrollToTop="True"> ...etc...
The search result control is placed inside another user control that uses the content header control (I will provide details if necessary).