using System.Collections.Specialized; using System.Windows; using System.Windows.Controls; namespace EmbyToolbox.Behaviors; public static class ListBoxAutoScrollBehavior { public static readonly DependencyProperty AutoScrollToEndProperty = DependencyProperty.RegisterAttached( "AutoScrollToEnd", typeof(bool), typeof(ListBoxAutoScrollBehavior), new PropertyMetadata(false, OnAutoScrollToEndChanged)); public static bool GetAutoScrollToEnd(DependencyObject obj) { return (bool)obj.GetValue(AutoScrollToEndProperty); } public static void SetAutoScrollToEnd(DependencyObject obj, bool value) { obj.SetValue(AutoScrollToEndProperty, value); } private static void OnAutoScrollToEndChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not ListBox listBox) { return; } if ((bool)e.NewValue) { listBox.Loaded += ListBoxOnLoaded; } else { listBox.Loaded -= ListBoxOnLoaded; UnhookCollection(listBox); } } private static void ListBoxOnLoaded(object sender, RoutedEventArgs e) { if (sender is not ListBox listBox) { return; } HookCollection(listBox); ScrollToLast(listBox); } private static void HookCollection(ListBox listBox) { if (listBox.ItemsSource is INotifyCollectionChanged collection) { collection.CollectionChanged -= OnCollectionChanged; collection.CollectionChanged += OnCollectionChanged; } } private static void UnhookCollection(ListBox listBox) { if (listBox.ItemsSource is INotifyCollectionChanged collection) { collection.CollectionChanged -= OnCollectionChanged; } } private static void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { if (sender is not INotifyCollectionChanged collection) { return; } foreach (Window window in Application.Current.Windows) { var listBox = FindListBoxForCollection(window, collection); if (listBox is not null) { ScrollToLast(listBox); return; } } } private static ListBox? FindListBoxForCollection(DependencyObject root, INotifyCollectionChanged collection) { if (root is ListBox listBox && ReferenceEquals(listBox.ItemsSource, collection)) { return listBox; } var childrenCount = System.Windows.Media.VisualTreeHelper.GetChildrenCount(root); for (var i = 0; i < childrenCount; i++) { var child = System.Windows.Media.VisualTreeHelper.GetChild(root, i); var found = FindListBoxForCollection(child, collection); if (found is not null) { return found; } } return null; } private static void ScrollToLast(ListBox listBox) { if (listBox.Items.Count <= 0) { return; } var last = listBox.Items[listBox.Items.Count - 1]; listBox.ScrollIntoView(last); } }