Code:
/ 4.0 / 4.0 / 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. //---------------------------------------------------------------------------- // // 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
- DataGridItemAutomationPeer.cs
- HMACSHA512.cs
- StrokeNodeData.cs
- _NativeSSPI.cs
- PageParserFilter.cs
- _IPv6Address.cs
- ContextProperty.cs
- WebPartHelpVerb.cs
- EpmContentSerializer.cs
- DragEventArgs.cs
- WindowsEditBoxRange.cs
- DataBindingHandlerAttribute.cs
- RoutedEventConverter.cs
- ItemList.cs
- TemplateBamlRecordReader.cs
- PasswordTextContainer.cs
- SecurityMessageProperty.cs
- Privilege.cs
- MemberMaps.cs
- MD5HashHelper.cs
- StringStorage.cs
- MappingItemCollection.cs
- XmlFormatReaderGenerator.cs
- WebScriptEnablingBehavior.cs
- DecoderExceptionFallback.cs
- EventBookmark.cs
- KnownTypesProvider.cs
- HTMLTextWriter.cs
- WorkflowViewStateService.cs
- ManagementExtension.cs
- FunctionNode.cs
- DeclarativeConditionsCollection.cs
- EntityDataSourceReferenceGroup.cs
- XmlCDATASection.cs
- SecureConversationSecurityTokenParameters.cs
- CryptoProvider.cs
- ExchangeUtilities.cs
- SoapSchemaMember.cs
- MatrixAnimationUsingKeyFrames.cs
- RichTextBoxDesigner.cs
- ListViewCommandEventArgs.cs
- WorkflowValidationFailedException.cs
- Literal.cs
- WebBrowserUriTypeConverter.cs
- SessionStateUtil.cs
- WmlCalendarAdapter.cs
- LinkTarget.cs
- MemberInfoSerializationHolder.cs
- XmlAttributeAttribute.cs
- XamlStackWriter.cs
- ControlParameter.cs
- LogAppendAsyncResult.cs
- ZipIORawDataFileBlock.cs
- OutputCacheSettingsSection.cs
- DateTimeSerializationSection.cs
- TemplateXamlParser.cs
- MailMessage.cs
- CanonicalFontFamilyReference.cs
- ClockGroup.cs
- VisemeEventArgs.cs
- FocusManager.cs
- User.cs
- MouseWheelEventArgs.cs
- IdentifierService.cs
- CipherData.cs
- SqlProviderServices.cs
- base64Transforms.cs
- CollectionConverter.cs
- TextCompositionEventArgs.cs
- ItemCheckEvent.cs
- SchemaImporter.cs
- DeviceContexts.cs
- EpmSourcePathSegment.cs
- ExecutionEngineException.cs
- DefaultProxySection.cs
- BitmapEffectOutputConnector.cs
- ObjectSet.cs
- XmlHierarchyData.cs
- BamlLocalizerErrorNotifyEventArgs.cs
- RawStylusInput.cs
- RawStylusInput.cs
- QueryStringConverter.cs
- EntityDataSourceEntitySetNameItem.cs
- HashCodeCombiner.cs
- CertificateReferenceElement.cs
- CodeDOMProvider.cs
- DataBoundControlHelper.cs
- CellQuery.cs
- Encoder.cs
- ApplicationCommands.cs
- SchemaAttDef.cs
- COM2Enum.cs
- SqlEnums.cs
- StylusPointPropertyUnit.cs
- XmlConvert.cs
- WebPartTransformerAttribute.cs
- RSAOAEPKeyExchangeDeformatter.cs
- OleDbMetaDataFactory.cs
- RepeatBehavior.cs
- StrongNameKeyPair.cs