using DTS.Common.Enums; using DTS.Common.Utilities.Logging; using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Interactivity; namespace DTS.Common.Behaviors { public class MultiSelectionBehavior : Behavior { protected override void OnAttached() { base.OnAttached(); if (SelectedItems != null) { AssociatedObject.SelectedItems.Clear(); foreach (var item in SelectedItems) { AssociatedObject.SelectedItems.Add(item); } } } public IList SelectedItems { get => (IList)GetValue(SelectedItemsProperty); set => SetValue(SelectedItemsProperty, value); } public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register("SelectedItems", typeof(IList), typeof(MultiSelectionBehavior), new UIPropertyMetadata(null, SelectedItemsChanged)); private static void SelectedItemsChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { var behavior = o as MultiSelectionBehavior; if (behavior == null) return; if (e.OldValue is INotifyCollectionChanged oldValue) { oldValue.CollectionChanged -= behavior.SourceCollectionChanged; behavior.AssociatedObject.SelectionChanged -= behavior.ListBoxSelectionChanged; } if (e.NewValue is INotifyCollectionChanged newValue) { behavior.AssociatedObject.SelectedItems.Clear(); foreach (var item in (IEnumerable)newValue) { behavior.AssociatedObject.SelectedItems.Add(item); } behavior.AssociatedObject.SelectionChanged += behavior.ListBoxSelectionChanged; newValue.CollectionChanged += behavior.SourceCollectionChanged; } } private bool _isUpdatingTarget; private bool _isUpdatingSource; private void SourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (_isUpdatingSource) return; try { _isUpdatingTarget = true; if (e.OldItems != null) { foreach (var item in e.OldItems) { AssociatedObject.SelectedItems.Remove(item); } } if (e.NewItems != null) { foreach (var item in e.NewItems) { AssociatedObject.SelectedItems.Add(item); } } if (e.Action == NotifyCollectionChangedAction.Reset) { AssociatedObject.SelectedItems.Clear(); } } finally { _isUpdatingTarget = false; } } private void ListBoxSelectionChanged(object sender, SelectionChangedEventArgs e) { if (_isUpdatingTarget) return; var selectedItems = SelectedItems; if (selectedItems == null) return; //this could be a bulk operation, turn off notifications if consumer is paying attention SelectedItemsStatus.SetUpdating(SelectedItems, true); try { _isUpdatingSource = true; foreach (var item in e.RemovedItems) { selectedItems.Remove(item); } var itemsToAdd = new List(); foreach (var item in e.AddedItems) { if (!selectedItems.Contains(item)) { itemsToAdd.Add(item); } } var type = selectedItems.GetType().GenericTypeArguments[0]; foreach (var item in itemsToAdd) { if (item == itemsToAdd.Last()) { //if this is the last item, turn notifications back on SelectedItemsStatus.SetUpdating(SelectedItems, false); } try { if (type.IsAssignableFrom(item.GetType())) { selectedItems.Add(item); } } catch (Exception ex) { APILogger.Log(ex); } } } finally { _isUpdatingSource = false; } } } }