diff --git a/FModel/Extensions/ListBoxExtensions.cs b/FModel/Extensions/ListBoxExtensions.cs new file mode 100644 index 00000000..8bcb2b17 --- /dev/null +++ b/FModel/Extensions/ListBoxExtensions.cs @@ -0,0 +1,36 @@ +using System.Windows.Controls; + +namespace FModel.Extensions; + +public static class ListBoxExtensions +{ + public static ListBoxItem RevealItem(this ListBox list, object item, bool alignToTop = false) + { + var index = list.Items.IndexOf(item); + if (index < 0) + return null; + + list.ApplyTemplate(); + list.UpdateLayout(); + if (alignToTop && list.FindVisualChild() is { } scroll) + { + scroll.ScrollToVerticalOffset(index); + list.UpdateLayout(); + } + + if (list.FindVisualChild() is { } panel) + { + panel.BringIndexIntoViewPublic(index); + } + else + { + list.ScrollIntoView(item); + } + + list.UpdateLayout(); + var container = list.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem; + container?.BringIntoView(); + list.UpdateLayout(); + return container; + } +} diff --git a/FModel/Extensions/VisualTreeExtensions.cs b/FModel/Extensions/VisualTreeExtensions.cs index 1a54a808..4072a552 100644 --- a/FModel/Extensions/VisualTreeExtensions.cs +++ b/FModel/Extensions/VisualTreeExtensions.cs @@ -17,4 +17,20 @@ public static class VisualTreeExtensions } return null; } + + public static T? FindVisualChild(this DependencyObject parent) where T : DependencyObject + { + for (var i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) + { + var child = VisualTreeHelper.GetChild(parent, i); + if (child is T result) + return result; + + if (FindVisualChild(child) is { } descendant) + return descendant; + } + + return null; + } + } diff --git a/FModel/Framework/RangeObservableCollection.cs b/FModel/Framework/RangeObservableCollection.cs index cf0b5261..3bdc5034 100644 --- a/FModel/Framework/RangeObservableCollection.cs +++ b/FModel/Framework/RangeObservableCollection.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.ComponentModel; namespace FModel.Framework; @@ -17,8 +18,7 @@ public sealed class RangeObservableCollection : ObservableCollection public void AddRange(IEnumerable list) { - if (list == null) - throw new ArgumentNullException(nameof(list)); + ArgumentNullException.ThrowIfNull(list); _suppressNotification = true; @@ -29,6 +29,24 @@ public sealed class RangeObservableCollection : ObservableCollection OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } + public void ReplaceRange(IEnumerable collection) + { + ArgumentNullException.ThrowIfNull(collection); + + var items = collection as IList ?? [.. collection]; + + CheckReentrancy(); + + Items.Clear(); + + foreach (var item in items) + Items.Add(item); + + OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count))); + OnPropertyChanged(new PropertyChangedEventArgs("Item[]")); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + } + public void SetSuppressionState(bool state) { _suppressNotification = state; @@ -38,4 +56,4 @@ public sealed class RangeObservableCollection : ObservableCollection { OnCollectionChanged(new NotifyCollectionChangedEventArgs(changedAction)); } -} \ No newline at end of file +} diff --git a/FModel/MainWindow.xaml b/FModel/MainWindow.xaml index 706f3755..39a178c6 100644 --- a/FModel/MainWindow.xaml +++ b/FModel/MainWindow.xaml @@ -344,16 +344,16 @@ - - - + + +