/// <summary> /// INotifyCollectionChanged.CollectionChanged handler for updating DataGrid.SelectedItems when the source list changes /// </summary> private static void UpdateDataGridsOnSourceCollectionChanged(object source, NotifyCollectionChangedEventArgs collectionChangedArgs) { DataGridsAndInitiatedSelectionChange sourceListInfo = ListViewMultipleSelection.selectedItemsSources[source.GetHashCode()]; // For each DataGrid that is bound to this list, is alive, and did not initate selection changes, update its selection sourceListInfo.InitiatedSelectionChange = true; IList sourceList = source as IList; Debug.Assert(sourceList != null, "SelectedItemsSource must be of type IList"); ListView dataGrid = null; foreach (WeakReference dataGridReference in sourceListInfo.BoundDataGridReferences) { if (dataGridReference.IsAlive && !ListViewMultipleSelection.GetInitiatedSelectionChange(dataGridReference.Target as ListView)) { dataGrid = dataGridReference.Target as ListView; UpdateDataGrid(dataGrid, sourceList, collectionChangedArgs); } } sourceListInfo.InitiatedSelectionChange = false; }
/// <summary> /// Updates the items source registry when the SelectedItemsSource for a DataGrid changes /// </summary> private static void SelectedItemsSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) { ListView dataGrid = sender as ListView; IList selectedItemsSource = null; // Check if the app is setting the source to a new or different list, or if it is removing the binding if (args.NewValue != null) { selectedItemsSource = args.NewValue as IList; if (selectedItemsSource == null) { throw new ArgumentException("The value for SelectedItemsSource must implement IList."); } INotifyCollectionChanged collection = args.NewValue as INotifyCollectionChanged; if (collection == null) { throw new ArgumentException("The value for SelectedItemsSource must implement INotifyCollectionChanged."); } // Don't add the event handler if the DataGrid is not setting its SelectedItemsSource for the first time if (args.OldValue == null) { // Sign up for changes to the DataGrid's selected items to enable a two-way binding effect dataGrid.SelectionChanged += UpdateSourceListOnDataGridSelectionChanged; } // Track this DataGrid instance for the specified source list DataGridsAndInitiatedSelectionChange sourceListInfo = null; if (ListViewMultipleSelection.selectedItemsSources.TryGetValue(selectedItemsSource.GetHashCode(), out sourceListInfo)) { sourceListInfo.BoundDataGridReferences.Add(new WeakReference(dataGrid)); } else { // This is a new source collection sourceListInfo = new DataGridsAndInitiatedSelectionChange() { InitiatedSelectionChange = false }; sourceListInfo.BoundDataGridReferences.Add(new WeakReference(dataGrid)); ListViewMultipleSelection.selectedItemsSources.Add(selectedItemsSource.GetHashCode(), sourceListInfo); // Sign up for changes to the source only on the first time the source is added collection.CollectionChanged += UpdateDataGridsOnSourceCollectionChanged; } // Now force the DataGrid to update its SelectedItems to match the current // contents of the source list sourceListInfo.InitiatedSelectionChange = true; UpdateDataGrid(dataGrid, selectedItemsSource, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); sourceListInfo.InitiatedSelectionChange = false; } else { // This DataGrid is removing its SelectedItems binding to any list dataGrid.SelectionChanged -= UpdateSourceListOnDataGridSelectionChanged; dataGrid.SelectedItems.Clear(); } if (args.OldValue != null) { // Clean up the items source that was the old value // Remove the DataGrid from the source list's registry and remove the source list // if there are no more DataGrids bound to it. DataGridsAndInitiatedSelectionChange sourceListInfo = ListViewMultipleSelection.selectedItemsSources[args.OldValue.GetHashCode()]; WeakReference dataGridReferenceNeedingRemoval = null; foreach (WeakReference dataGridReference in sourceListInfo.BoundDataGridReferences) { if (dataGridReference.IsAlive && (dataGridReference.Target == dataGrid)) { dataGridReferenceNeedingRemoval = dataGridReference; break; } } sourceListInfo.BoundDataGridReferences.Remove(dataGridReferenceNeedingRemoval); if (sourceListInfo.BoundDataGridReferences.Count == 0) { ListViewMultipleSelection.selectedItemsSources.Remove(args.OldValue.GetHashCode()); // Detach the event handlers and clear DataGrid.SelectedItems since the source is now null INotifyCollectionChanged collection = args.OldValue as INotifyCollectionChanged; if (collection != null) { collection.CollectionChanged -= UpdateDataGridsOnSourceCollectionChanged; } } } }