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
- BaseTreeIterator.cs
- TransactionsSectionGroup.cs
- ExtensionSimplifierMarkupObject.cs
- ReaderOutput.cs
- EndpointAddressMessageFilterTable.cs
- MinMaxParagraphWidth.cs
- DrawingImage.cs
- DBSqlParserColumn.cs
- ResizingMessageFilter.cs
- Converter.cs
- ViewBox.cs
- EmbeddedMailObjectsCollection.cs
- ReferenceSchema.cs
- InvalidWMPVersionException.cs
- HttpRequest.cs
- ChooseAction.cs
- ByteViewer.cs
- OdbcConnectionPoolProviderInfo.cs
- TraceContextEventArgs.cs
- ResourceReferenceExpression.cs
- Crypto.cs
- assertwrapper.cs
- SessionParameter.cs
- loginstatus.cs
- ReflectionUtil.cs
- ActionNotSupportedException.cs
- PrePrepareMethodAttribute.cs
- HierarchicalDataBoundControl.cs
- TranslateTransform3D.cs
- OrderByQueryOptionExpression.cs
- ReferencedCollectionType.cs
- LayoutEvent.cs
- WebControlAdapter.cs
- TimeSpanValidator.cs
- TcpAppDomainProtocolHandler.cs
- SafeTokenHandle.cs
- EventSinkActivityDesigner.cs
- XmlSubtreeReader.cs
- ToolStripItemCollection.cs
- TypeName.cs
- RuntimeEnvironment.cs
- HttpWebRequestElement.cs
- WebConfigurationHost.cs
- CompareInfo.cs
- SoapBinding.cs
- OdbcCommandBuilder.cs
- SchemaNames.cs
- WebPartZone.cs
- UriTemplatePathSegment.cs
- ResourcePermissionBaseEntry.cs
- Misc.cs
- WindowsFormsHelpers.cs
- SerializationFieldInfo.cs
- ToolStripPanelCell.cs
- BitmapEffectrendercontext.cs
- LedgerEntryCollection.cs
- MemoryFailPoint.cs
- TextFindEngine.cs
- ServiceOperationParameter.cs
- FramingChannels.cs
- GenericTypeParameterBuilder.cs
- Vector3DConverter.cs
- PointLightBase.cs
- SettingsPropertyIsReadOnlyException.cs
- TextDecorationCollectionConverter.cs
- DBDataPermission.cs
- HtmlInputImage.cs
- SerializationInfoEnumerator.cs
- HatchBrush.cs
- CacheEntry.cs
- ObsoleteAttribute.cs
- BitmapPalette.cs
- ForeignKeyConstraint.cs
- RegexReplacement.cs
- PackageRelationship.cs
- RequestDescription.cs
- HostedElements.cs
- ToolCreatedEventArgs.cs
- DataControlImageButton.cs
- HttpPostProtocolReflector.cs
- Encoder.cs
- FileIOPermission.cs
- AccessDataSourceView.cs
- CommandBindingCollection.cs
- Point4DConverter.cs
- XmlDownloadManager.cs
- GeneralTransformGroup.cs
- ExtensionElement.cs
- ItemChangedEventArgs.cs
- RijndaelCryptoServiceProvider.cs
- SqlDataSourceFilteringEventArgs.cs
- OleStrCAMarshaler.cs
- SapiRecognizer.cs
- EventData.cs
- BindingSource.cs
- QueryContinueDragEvent.cs
- ResourceExpressionBuilder.cs
- SqlClientWrapperSmiStreamChars.cs
- WorkerRequest.cs
- PackageDigitalSignatureManager.cs