Advertisement
bobmarley12345

WPF Binding SelectedItems property

Aug 7th, 2023
878
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.28 KB | None | 0 0
  1. using System.Collections;
  2. using System.Collections.Specialized;
  3. using System.Windows;
  4. using System.Windows.Controls;
  5. using System.Windows.Controls.Primitives;
  6. using FramePFX.Core.Utils;
  7.  
  8. namespace FramePFX.AttachedProperties {
  9.     /// <summary>
  10.     /// A helper class for binding selected item collections.
  11.     /// <para>
  12.     /// When using observable collections, you just bind it directly and then handle the collection changed events in your code
  13.     /// </para>
  14.     /// <para>
  15.     /// When using a normal list (that does not implement <see cref="INotifyCollectionChanged"/>), ensure the list is non-null at
  16.     /// all times. This class will set the list property (when the selected items change) to the same instance,
  17.     /// allowing you to handle the change in your property's setter
  18.     /// </para>
  19.     /// </summary>
  20.     public static class MultiSelectorHelper {
  21.         public static readonly DependencyProperty SelectedItemsProperty =
  22.             DependencyProperty.RegisterAttached(
  23.                 "SelectedItems",
  24.                 typeof(IList),
  25.                 typeof(MultiSelectorHelper),
  26.                 new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedItemsChanged));
  27.  
  28.         public static readonly DependencyProperty UpdateSelectedItemsOnChangeProperty =
  29.             DependencyProperty.RegisterAttached(
  30.                 "UpdateSelectedItemsOnChange",
  31.                 typeof(bool),
  32.                 typeof(MultiSelectorHelper),
  33.                 new PropertyMetadata(BoolBox.True, OnUpdateSelectedItemsOnChangeChanged));
  34.  
  35.         private static readonly DependencyPropertyKey IsUpdatingSelectionProperty =
  36.             DependencyProperty.RegisterAttachedReadOnly(
  37.                 "IsUpdatingSelection",
  38.                 typeof(bool),
  39.                 typeof(MultiSelectorHelper),
  40.                 new PropertyMetadata(BoolBox.False));
  41.  
  42.         public static IList GetSelectedItems(DependencyObject obj) {
  43.             return (IList) obj.GetValue(SelectedItemsProperty);
  44.         }
  45.  
  46.         public static void SetSelectedItems(DependencyObject obj, IList value) {
  47.             obj.SetValue(SelectedItemsProperty, value);
  48.         }
  49.  
  50.         public static bool GetUpdateSelectedItemsOnChange(DependencyObject obj) {
  51.             return (bool) obj.GetValue(UpdateSelectedItemsOnChangeProperty);
  52.         }
  53.  
  54.         public static void SetUpdateSelectedItemsOnChange(DependencyObject obj, bool value) {
  55.             obj.SetValue(UpdateSelectedItemsOnChangeProperty, value.Box());
  56.         }
  57.  
  58.         private static void SetIsUpdatingSelection(DependencyObject element, bool value) {
  59.             element.SetValue(IsUpdatingSelectionProperty, value.Box());
  60.         }
  61.  
  62.         private static bool GetIsUpdatingSelection(DependencyObject element) {
  63.             return (bool) element.GetValue(IsUpdatingSelectionProperty.DependencyProperty);
  64.         }
  65.  
  66.         private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
  67.             if (GetIsUpdatingSelection(d)) {
  68.                 return;
  69.             }
  70.  
  71.             if (d is Selector) {
  72.                 SetIsUpdatingSelection(d, true);
  73.                 try {
  74.                     IList list;
  75.                     if (d is ListBox box) {
  76.                         list = box.SelectedItems;
  77.                     }
  78.                     else if (d is MultiSelector ms) {
  79.                         list = ms.SelectedItems;
  80.                     }
  81.                     else {
  82.                         list = null;
  83.                     }
  84.  
  85.                     if (list != null) {
  86.                         list.Clear();
  87.                         if (e.NewValue is IList selectedItems) {
  88.                             foreach (object item in selectedItems) {
  89.                                 list.Add(item);
  90.                             }
  91.                         }
  92.                     }
  93.                 }
  94.                 finally {
  95.                     SetIsUpdatingSelection(d, false);
  96.                 }
  97.             }
  98.  
  99.             TryRegisterEvents(d);
  100.         }
  101.  
  102.         private static void TryRegisterEvents(DependencyObject obj) {
  103.             if (GetUpdateSelectedItemsOnChange(obj)) {
  104.                 if (obj is Selector selector) {
  105.                     selector.SelectionChanged -= OnSelectionChanged;
  106.                     selector.SelectionChanged += OnSelectionChanged;
  107.                 }
  108.             }
  109.         }
  110.  
  111.         private static void OnUpdateSelectedItemsOnChangeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
  112.             if (d is Selector selector) {
  113.                 selector.SelectionChanged -= OnSelectionChanged;
  114.                 if ((bool) e.NewValue) {
  115.                     selector.SelectionChanged += OnSelectionChanged;
  116.                 }
  117.             }
  118.         }
  119.  
  120.         private static bool ListEquals(IList a, IList b) {
  121.             int cA = a.Count, cB = b.Count;
  122.             if (cA != cB) {
  123.                 return false;
  124.             }
  125.  
  126.             for (int i = 0; i < cA; i++) {
  127.                 if (!ReferenceEquals(a[i], b[i])) {
  128.                     return false;
  129.                 }
  130.             }
  131.  
  132.             return true;
  133.         }
  134.  
  135.         private static void OnSelectionChanged(object sender, SelectionChangedEventArgs e) {
  136.             if (sender is Selector selector) {
  137.                 if (GetIsUpdatingSelection(selector)) {
  138.                     return;
  139.                 }
  140.  
  141.                 IList selectedItems = GetSelectedItems(selector);
  142.                 if (selectedItems == null) {
  143.                     return;
  144.                 }
  145.  
  146.                 try {
  147.                     IList src;
  148.                     switch (selector) {
  149.                         case ListBox lb: src = lb.SelectedItems; break;
  150.                         case MultiSelector ms: src = ms.SelectedItems; break;
  151.                         default: src = null; break;
  152.                     }
  153.  
  154.                     if (src != null) {
  155.                         // Can massively improve performance for property pages
  156.                         if (ListEquals(src, selectedItems)) {
  157.                             return;
  158.                         }
  159.  
  160.                         SetIsUpdatingSelection(selector, true);
  161.  
  162.                         selectedItems.Clear();
  163.                         foreach (object item in src)
  164.                             selectedItems.Add(item);
  165.                     }
  166.                     else {
  167.                         SetIsUpdatingSelection(selector, true);
  168.                         if (e.RemovedItems != null) {
  169.                             foreach (object value in e.RemovedItems) {
  170.                                 selectedItems.Remove(value);
  171.                             }
  172.                         }
  173.  
  174.                         if (e.AddedItems != null) {
  175.                             foreach (object value in e.AddedItems) {
  176.                                 selectedItems.Add(value);
  177.                             }
  178.                         }
  179.                     }
  180.  
  181.                     if (!(selectedItems is INotifyCollectionChanged))
  182.                         SetSelectedItems(selector, selectedItems);
  183.                 }
  184.                 finally {
  185.                     SetIsUpdatingSelection(selector, false);
  186.                 }
  187.             }
  188.         }
  189.     }
  190. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement