Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / MultipleCopiesCollection.cs / 1305600 / MultipleCopiesCollection.cs
//---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // //--------------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Windows.Data; namespace System.Windows.Controls { ////// A collection that simulates holding multiple copies of the same item. Used as the ItemsSource for the DataGridCellsPresenter. /// For our purposes this mirrors the DataGrid.Columns collection in that it has the same number of items and changes whenever /// the columns collection changes (though the items in it are obviously different; each item is the data object for a given row). /// internal class MultipleCopiesCollection : IList, ICollection, IEnumerable, INotifyCollectionChanged, INotifyPropertyChanged { #region Construction internal MultipleCopiesCollection(object item, int count) { Debug.Assert(item != null, "item should not be null."); Debug.Assert(count >= 0, "count should not be negative."); CopiedItem = item; _count = count; } #endregion #region Item Management ////// Takes a collection change notifcation and causes the MultipleCopies collection to [....] to the changes. For example, /// if an item was removed at a given index, the MultipleCopiesCollection also removes an item at the same index and fires /// its own collection changed event. /// internal void MirrorCollectionChange(NotifyCollectionChangedEventArgs e) { switch (e.Action) { case NotifyCollectionChangedAction.Add: Debug.Assert( e.NewItems.Count == 1, "We're mirroring the Columns collection which is an ObservableCollection and only supports adding one item at a time"); Insert(e.NewStartingIndex); break; case NotifyCollectionChangedAction.Move: Debug.Assert( e.NewItems.Count == 1, "We're mirroring the Columns collection which is an ObservableCollection and only supports moving one item at a time"); Move(e.OldStartingIndex, e.NewStartingIndex); break; case NotifyCollectionChangedAction.Remove: Debug.Assert( e.OldItems.Count == 1, "We're mirroring the Columns collection which is an ObservableCollection and only supports removing one item at a time"); RemoveAt(e.OldStartingIndex); break; case NotifyCollectionChangedAction.Replace: Debug.Assert( e.NewItems.Count == 1, "We're mirroring the Columns collection which is an ObservableCollection and only supports replacing one item at a time"); OnReplace(CopiedItem, CopiedItem, e.NewStartingIndex); break; case NotifyCollectionChangedAction.Reset: Reset(); break; } } ////// Syncs up the count with the given one. This is used when we know we've missed a CollectionChanged event (say this /// MultipleCopiesCollection is inside a DataGridRow that was virtualized and recycled). It attempts to resync /// by adjusting the count and firing the proper property change notifications. /// ////// This method works in concert with the DataGridCellsPresenter. We don't know where items were removed / added, so containers /// (DataGridCells) based off this collection could be stale (wrong column). The cells presenter updates them. We could have also /// just fired a Reset event here and not bothered with work in the cells presenter, but that would cause all cells to be regenerated. /// /// Note that this method is designed to [....] up to ALL collection changes that may have happened. /// The job of this method is made significantly easier by the fact that the MultipleCopiesCollection really only cares about /// the count of items in the given collection (since we keep it in [....] with the DataGrid Columns collection but host /// a DataGridRow as the item). This means we don't care about Move, Replace, etc. /// internal void SyncToCount(int newCount) { int oldCount = RepeatCount; if (newCount != oldCount) { if (newCount > oldCount) { // Insert at end InsertRange(oldCount, newCount - oldCount); } else { // Remove from the end int numToRemove = oldCount - newCount; RemoveRange(oldCount - numToRemove, numToRemove); } Debug.Assert(RepeatCount == newCount, "We should have properly updated the RepeatCount"); } } ////// This is the item that is returned multiple times. /// internal object CopiedItem { get { return _item; } set { if (value == CollectionView.NewItemPlaceholder) { // If we populate the collection with the CollectionView's // NewItemPlaceholder, it will confuse the CollectionView. value = DataGrid.NewItemPlaceholder; } if (_item != value) { object oldValue = _item; _item = value; OnPropertyChanged(IndexerName); // Report replacing each item with the new item for (int i = 0; i < _count; i++) { OnReplace(oldValue, _item, i); } } } } ////// This is the number of times the item is to be repeated. /// private int RepeatCount { get { return _count; } set { if (_count != value) { _count = value; OnPropertyChanged(CountName); OnPropertyChanged(IndexerName); } } } private void Insert(int index) { RepeatCount++; OnCollectionChanged(NotifyCollectionChangedAction.Add, CopiedItem, index); } private void InsertRange(int index, int count) { // True range operations are not supported by CollectionView so we instead fire many changed events. for (int i = 0; i < count; i++) { Insert(index); index++; } } private void Move(int oldIndex, int newIndex) { OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, CopiedItem, newIndex, oldIndex)); } private void RemoveAt(int index) { Debug.Assert((index >= 0) && (index < RepeatCount), "Index out of range"); RepeatCount--; OnCollectionChanged(NotifyCollectionChangedAction.Remove, CopiedItem, index); } private void RemoveRange(int index, int count) { // True range operations are not supported by CollectionView so we instead fire many changed events. for (int i = 0; i < count; i++) { RemoveAt(index); } } private void OnReplace(object oldItem, object newItem, int index) { OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newItem, oldItem, index)); } private void Reset() { RepeatCount = 0; OnCollectionReset(); } #endregion #region IList Members public int Add(object value) { throw new NotSupportedException(SR.Get(SRID.DataGrid_ReadonlyCellsItemsSource)); } public void Clear() { throw new NotSupportedException(SR.Get(SRID.DataGrid_ReadonlyCellsItemsSource)); } public bool Contains(object value) { if (value == null) { throw new ArgumentNullException("value"); } return _item == value; } public int IndexOf(object value) { if (value == null) { throw new ArgumentNullException("value"); } return (_item == value) ? 0 : -1; } public void Insert(int index, object value) { throw new NotSupportedException(SR.Get(SRID.DataGrid_ReadonlyCellsItemsSource)); } public bool IsFixedSize { get { return false; } } public bool IsReadOnly { get { return true; } } public void Remove(object value) { throw new NotSupportedException(SR.Get(SRID.DataGrid_ReadonlyCellsItemsSource)); } void IList.RemoveAt(int index) { throw new NotSupportedException(SR.Get(SRID.DataGrid_ReadonlyCellsItemsSource)); } public object this[int index] { get { if ((index >= 0) && (index < RepeatCount)) { Debug.Assert(_item != null, "_item should be non-null."); return _item; } else { throw new ArgumentOutOfRangeException("index"); } } set { throw new InvalidOperationException(); } } #endregion #region ICollection Members public void CopyTo(Array array, int index) { throw new NotSupportedException(); } public int Count { get { return RepeatCount; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } #endregion #region IEnumerable Members public IEnumerator GetEnumerator() { return new MultipleCopiesCollectionEnumerator(this); } private class MultipleCopiesCollectionEnumerator : IEnumerator { public MultipleCopiesCollectionEnumerator(MultipleCopiesCollection collection) { _collection = collection; _item = _collection.CopiedItem; _count = _collection.RepeatCount; _current = -1; } #region IEnumerator Members object IEnumerator.Current { get { if (_current >= 0) { if (_current < _count) { return _item; } else { throw new InvalidOperationException(); } } else { return null; } } } bool IEnumerator.MoveNext() { if (IsCollectionUnchanged) { int newIndex = _current + 1; if (newIndex < _count) { _current = newIndex; return true; } return false; } else { throw new InvalidOperationException(); } } void IEnumerator.Reset() { if (IsCollectionUnchanged) { _current = -1; } else { throw new InvalidOperationException(); } } private bool IsCollectionUnchanged { get { return (_collection.RepeatCount == _count) && (_collection.CopiedItem == _item); } } #endregion #region Data private object _item; private int _count; private int _current; private MultipleCopiesCollection _collection; #endregion } #endregion #region INotifyCollectionChanged Members public event NotifyCollectionChangedEventHandler CollectionChanged; ////// Helper to raise a CollectionChanged event when an item is added or removed. /// private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index) { OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index)); } ////// Helper to raise a CollectionChanged event when the collection is cleared. /// private void OnCollectionReset() { OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } private void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (CollectionChanged != null) { CollectionChanged(this, e); } } #endregion #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; ////// Helper to raise a PropertyChanged event. /// private void OnPropertyChanged(string propertyName) { OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); } private void OnPropertyChanged(PropertyChangedEventArgs e) { if (PropertyChanged != null) { PropertyChanged(this, e); } } #endregion #region Data private object _item; // private int _count; private const string CountName = "Count"; private const string IndexerName = "Item[]"; #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ColumnWidthChangingEvent.cs
- RemotingSurrogateSelector.cs
- ConstructorBuilder.cs
- LayoutDump.cs
- ISFClipboardData.cs
- DataGridViewTextBoxCell.cs
- ObjectAnimationBase.cs
- DrawingAttributeSerializer.cs
- XD.cs
- RequestUriProcessor.cs
- SqlCacheDependencySection.cs
- DataShape.cs
- ToolStripHighContrastRenderer.cs
- ConfigXmlElement.cs
- ClientSponsor.cs
- panel.cs
- WindowsToolbar.cs
- OneOfScalarConst.cs
- DataColumnSelectionConverter.cs
- HostedController.cs
- XmlAttributeCollection.cs
- ErrorTableItemStyle.cs
- HttpCacheParams.cs
- SafeRightsManagementQueryHandle.cs
- ControlCollection.cs
- ProviderUtil.cs
- RbTree.cs
- ResourceIDHelper.cs
- AppLevelCompilationSectionCache.cs
- DataBoundControlHelper.cs
- JsonFormatMapping.cs
- BitmapImage.cs
- EnvironmentPermission.cs
- StringConcat.cs
- SqlCacheDependencyDatabaseCollection.cs
- DataServiceConfiguration.cs
- SearchForVirtualItemEventArgs.cs
- Environment.cs
- CompilerHelpers.cs
- MdiWindowListItemConverter.cs
- StringUtil.cs
- validation.cs
- EventBindingService.cs
- ParsedAttributeCollection.cs
- XmlSchemaImporter.cs
- ParentQuery.cs
- MetaChildrenColumn.cs
- LinqDataSourceDisposeEventArgs.cs
- ToolStripAdornerWindowService.cs
- RefreshInfo.cs
- CodeGroup.cs
- HelpProvider.cs
- RangeValuePattern.cs
- XPathParser.cs
- WebPartTransformerAttribute.cs
- DynamicMetaObject.cs
- MaterialGroup.cs
- OleDbReferenceCollection.cs
- Rule.cs
- MetadataPropertyAttribute.cs
- XmlSchemaExternal.cs
- ErrorHandler.cs
- XmlSchemaIdentityConstraint.cs
- EntityDataSourceWizardForm.cs
- DataObjectPastingEventArgs.cs
- DrawListViewItemEventArgs.cs
- SwitchAttribute.cs
- Listbox.cs
- ErrorProvider.cs
- HwndSourceKeyboardInputSite.cs
- ComponentEvent.cs
- CompiledQuery.cs
- CompoundFileStreamReference.cs
- MergeFilterQuery.cs
- EntityProviderFactory.cs
- BindingNavigator.cs
- PointUtil.cs
- PopOutPanel.cs
- FontWeights.cs
- DataServiceClientException.cs
- NonParentingControl.cs
- URLMembershipCondition.cs
- DescendantOverDescendantQuery.cs
- TextTreeExtractElementUndoUnit.cs
- EntityParameter.cs
- ComponentChangingEvent.cs
- ReaderWriterLock.cs
- BamlRecordHelper.cs
- TreeNodeBindingCollection.cs
- Logging.cs
- PopupRoot.cs
- WebControl.cs
- NavigationWindowAutomationPeer.cs
- TableLayout.cs
- DrawingContextDrawingContextWalker.cs
- OdbcPermission.cs
- BaseDataListActionList.cs
- TypeConverterValueSerializer.cs
- CqlBlock.cs
- Repeater.cs