Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Documents / TextElementCollection.cs / 1305600 / TextElementCollection.cs
//---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // // Description: Generic type for TextElement collections // //--------------------------------------------------------------------------- namespace System.Windows.Documents { using System.Collections; // IList using System.Collections.Generic; // ICollectionusing System.Windows.Controls; // TextBlock, ContentControl and AccessText using MS.Internal; // Invariant using MS.Internal.Documents; // FlowDocumentView /// /// public class TextElementCollection: IList, ICollection where TextElementType : TextElement { //------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors /// /// /// /// Owner of this TextElementCollection. /// In case when a collection is created for children of a parent, owner is the parent object. /// In case when a collection is created as a sibling collection of a TextElement, owner is that TextElement object. /// This distinction is very important, so that a collection belongs semantically to the owner it was created for. /// /// /// Flag indicating if the owner is a parent of objects in this collection or is a member object. /// internal TextElementCollection(DependencyObject owner, bool isOwnerParent) { if (isOwnerParent) { Invariant.Assert(owner is TextElement || owner is FlowDocument || owner is TextBlock); } else { Invariant.Assert(owner is TextElement); } _owner = owner; _isOwnerParent = isOwnerParent; _indexCache = new ElementIndexCache(-1, null); } #endregion Constructors //-------------------------------------------------------------------- // // Public Methods // //------------------------------------------------------------------- #region Public Methods //................................................................... // // ICollectionMembers // //................................................................... #region ICollection Members /// /// Adds an unlinked TextElement item to the end of this collection. /// /// public void Add(TextElementType item) { if (item == null) { throw new ArgumentNullException("item"); } ValidateChild(item); this.TextContainer.BeginChange(); try { item.RepositionWithContent(this.ContentEnd); } finally { this.TextContainer.EndChange(); } } ////// public void Clear() { // Note: We need to remember the textcontainer for any delete operations in this collection. // This is important for the case when the owner of the collection is a sibling member. // In a scenario where you remove the owner itself from the collection, // the owner belongs to another tree after the reposition. TextContainer textContainer = this.TextContainer; textContainer.BeginChange(); try { textContainer.DeleteContentInternal(this.ContentStart, this.ContentEnd); } finally { textContainer.EndChange(); } } ////// /// ///public bool Contains(TextElementType item) { if (item == null) { return false; } TextElementType element; for (element = this.FirstChild; element != null; element = (TextElementType)element.NextElement) { if (element == item) break; } return (element == item); } /// /// /// /// /// public void CopyTo(TextElementType[] array, int arrayIndex) { ((ICollection)this).CopyTo(array, arrayIndex); } ////// /// public int Count { get { int count = 0; TextElement element; if (_indexCache.IsValid(this)) { element = _indexCache.Element; count += _indexCache.Index; } else { element = this.FirstChild; } while (element != null) { count++; element = element.NextElement; } return count; } } ////// /// public bool IsReadOnly { get { return false; } } ////// Removes an item from a collection and from a tree. /// The element removed can be re-inserted later in another collection of a tree. /// /// ////// True if removal was successful. /// public bool Remove(TextElementType item) { if (item == null) { return false; } if (item.Parent != this.Parent) { return false; } // Note: We need to remember the textcontainer for any delete operations in this collection. // This is important for the case when the owner of the collection is a sibling member. // In a scenario where you remove the owner itself from the collection, // the owner belongs to another tree after the reposition. TextContainer textContainer = this.TextContainer; textContainer.BeginChange(); try { item.RepositionWithContent(null); } finally { textContainer.EndChange(); } return true; } #endregion ICollectionMembers /// /// Inserts a unlinked TextElement newItem after previousSibling, which is supposed to be an existing member of this collection. /// /// /// TextElement after which the newItem is to be inserted /// /// /// A TextElement to be inserted into the collection after the previousSibling. /// It must be unlinked from a tree before insertion. /// public void InsertAfter(TextElementType previousSibling, TextElementType newItem) { if (previousSibling == null) { throw new ArgumentNullException("previousSibling"); } if (newItem == null) { throw new ArgumentNullException("newItem"); } if (previousSibling.Parent != this.Parent) { throw new InvalidOperationException(SR.Get(SRID.TextElementCollection_PreviousSiblingDoesNotBelongToThisCollection, previousSibling.GetType().Name)); } if (newItem.Parent != null) { throw new ArgumentException(SR.Get(SRID.TextSchema_TheChildElementBelongsToAnotherTreeAlready, this.GetType().Name)); } ValidateChild(newItem); this.TextContainer.BeginChange(); try { newItem.RepositionWithContent(previousSibling.ElementEnd); } finally { this.TextContainer.EndChange(); } } ////// Inserts a TextElement newItem into a collection before a nextSibling TextElement. /// /// /// TextElement before which the newItem is to be inserted /// /// /// A TextElement to be inserted into the collection before the nextSibling. /// It must be unlinked from a tree before insertion. /// public void InsertBefore(TextElementType nextSibling, TextElementType newItem) { if (nextSibling == null) { throw new ArgumentNullException("nextSibling"); } if (newItem == null) { throw new ArgumentNullException("newItem"); } if (nextSibling.Parent != this.Parent) { throw new InvalidOperationException(SR.Get(SRID.TextElementCollection_NextSiblingDoesNotBelongToThisCollection, nextSibling.GetType().Name)); } if (newItem.Parent != null) { throw new ArgumentException(SR.Get(SRID.TextSchema_TheChildElementBelongsToAnotherTreeAlready, this.GetType().Name)); } ValidateChild(newItem); this.TextContainer.BeginChange(); try { newItem.RepositionWithContent(nextSibling.ElementStart); } finally { this.TextContainer.EndChange(); } } ////// Adds the elements of an IEnumerable to this collection. /// /// /// Elements to add. /// public void AddRange(IEnumerable range) { if (range == null) { throw new ArgumentNullException("range"); } IEnumerator enumerator = range.GetEnumerator(); if (enumerator == null) { throw new ArgumentException(SR.Get(SRID.TextElementCollection_NoEnumerator), "range"); } this.TextContainer.BeginChange(); try { while (enumerator.MoveNext()) { TextElementType element = enumerator.Current as TextElementType; if (element == null) { // throw new ArgumentException(SR.Get(SRID.TextElementCollection_ItemHasUnexpectedType, "range", typeof(TextElementType).Name, typeof(TextElementType).Name), "value"); } Add(element); } } finally { this.TextContainer.EndChange(); } } //................................................................... // // IEnumerableMembers // //................................................................... #region IEnumerable Members /// /// /// ///public IEnumerator GetEnumerator() { return new TextElementEnumerator (this.ContentStart, this.ContentEnd); } #endregion IEnumerable Members //................................................................... // // IEnumerable Members // //................................................................... #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return new RangeContentEnumerator(this.ContentStart, this.ContentEnd); } #endregion IEnumerable Members //................................................................... // // IList Members // //................................................................... #region IList Members /// /// Method that does the work for IList.Add. /// internal virtual int OnAdd(object value) { if (value == null) { throw new ArgumentNullException("value"); } if (!(value is TextElementType)) { throw new ArgumentException(SR.Get(SRID.TextElementCollection_TextElementTypeExpected, typeof(TextElementType).Name), "value"); } ValidateChild((TextElementType)value); this.TextContainer.BeginChange(); try { bool isCacheSafePreviousIndex = _indexCache.IsValid(this); this.Add((TextElementType)value); return IndexOfInternal(value, isCacheSafePreviousIndex); } finally { this.TextContainer.EndChange(); } } int IList.Add(object value) { return OnAdd(value); } void IList.Clear() { this.Clear(); } bool IList.Contains(object value) { TextElementType item = value as TextElementType; if (item == null) { return false; } return this.Contains(item); } int IList.IndexOf(object value) { return IndexOfInternal(value, false /* isCacheSafePreviousIndex */); } void IList.Insert(int index, object value) { if (value == null) { throw new ArgumentNullException("value"); } TextElementType newItem = value as TextElementType; if (newItem == null) { throw new ArgumentException(SR.Get(SRID.TextElementCollection_TextElementTypeExpected, typeof(TextElementType).Name), "value"); } if (index < 0) { throw new IndexOutOfRangeException(SR.Get(SRID.TextElementCollection_IndexOutOfRange)); } if (newItem.Parent != null) { throw new ArgumentException(SR.Get(SRID.TextSchema_TheChildElementBelongsToAnotherTreeAlready, this.GetType().Name)); } ValidateChild(newItem); this.TextContainer.BeginChange(); try { TextPointer position; if (this.FirstChild == null) { if (index != 0) { throw new IndexOutOfRangeException(SR.Get(SRID.TextElementCollection_IndexOutOfRange)); } position = this.ContentStart; } else { bool atCollectionEnd; TextElementType element = GetElementAtIndex(index, out atCollectionEnd); if (!atCollectionEnd && element == null) { throw new IndexOutOfRangeException(SR.Get(SRID.TextElementCollection_IndexOutOfRange)); } position = atCollectionEnd ? this.ContentEnd : element.ElementStart; } position.InsertTextElement(newItem); SetCache(index, newItem); } finally { this.TextContainer.EndChange(); } } bool IList.IsFixedSize { get { return false; } } bool IList.IsReadOnly { get { return this.IsReadOnly; } } void IList.Remove(object value) { TextElementType item = value as TextElementType; if (item == null) { return; } this.Remove(item); } void IList.RemoveAt(int index) { RemoveAtInternal(index); } object IList.this[int index] { get { if (index < 0) { throw new IndexOutOfRangeException(SR.Get(SRID.TextElementCollection_IndexOutOfRange)); } TextElementType element = GetElementAtIndex(index); if (element == null) { throw new IndexOutOfRangeException(SR.Get(SRID.TextElementCollection_IndexOutOfRange)); } SetCache(index, element); return element; } set { if (value == null) { throw new ArgumentNullException("value"); } if (!(value is TextElementType)) { throw new ArgumentException(SR.Get(SRID.TextElementCollection_TextElementTypeExpected, typeof(TextElementType).Name), "value"); } ValidateChild((TextElementType)value); this.TextContainer.BeginChange(); try { // Remove old element. TextElementType nextElement = RemoveAtInternal(index); // Insert new element. TextPointer position = (nextElement == null) ? this.ContentEnd : nextElement.ElementStart; position.InsertTextElement((TextElementType)value); // Reset the cache. SetCache(index, (TextElementType)value); } finally { this.TextContainer.EndChange(); } } } #endregion IList Members #region ICollection Members void ICollection.CopyTo(Array array, int arrayIndex) { int count = this.Count; if (array == null) { throw new ArgumentNullException("array"); } Type elementType = array.GetType().GetElementType(); if (elementType == null || !elementType.IsAssignableFrom(typeof(TextElementType))) { throw new ArgumentException("array"); } if (arrayIndex < 0) { throw new ArgumentOutOfRangeException("arrayIndex"); } if (arrayIndex > array.Length) { throw new ArgumentException("arrayIndex"); } if (array.Length < arrayIndex + count) { throw new ArgumentException(SR.Get(SRID.TextElementCollection_CannotCopyToArrayNotSufficientMemory, count, arrayIndex, array.Length)); } for (TextElementType element = (TextElementType)this.FirstChild; element != null; element = (TextElementType)element.NextElement) { array.SetValue(element, arrayIndex++); } } int ICollection.Count { get { return this.Count; } } bool ICollection.IsSynchronized { get { // return true; } } object ICollection.SyncRoot { get { // return this.TextContainer; } } #endregion ICollection Members #endregion Public Methods //-------------------------------------------------------------------- // // Internal Properties // //-------------------------------------------------------------------- #region Internal Properties // Owner of this TextElementCollection. // In case when a collection is created for children of a parent, owner is the parent object. // In case when a collection is created as a sibling collection of a TextElement, owner is that TextElement object. // This distinction is very important, so that a collection belongs semantically to the owner it was created for. internal DependencyObject Owner { get { return _owner; } } // Parent of all TextElementType objects in this collection. // Note that a parent may or may not be the owner of the collection. internal DependencyObject Parent { get { return _isOwnerParent ? _owner : ((TextElement)_owner).Parent; } } // The TextContainer associated with this collection's parent. internal TextContainer TextContainer { get { TextContainer textContainer; if (_owner is TextBlock) { textContainer = (TextContainer)((TextBlock)_owner).TextContainer; } else if (_owner is FlowDocument) { textContainer = ((FlowDocument)_owner).TextContainer; } else { textContainer = ((TextElement)_owner).TextContainer; } return textContainer; } } ////// Returns a first item of this collection /// internal TextElementType FirstChild { get { TextElementType firstChild; if (this.Parent is TextElement) { firstChild = (TextElementType)((TextElement)this.Parent).FirstChildElement; } else { TextTreeTextElementNode node = this.TextContainer.FirstContainedNode as TextTreeTextElementNode; firstChild = (TextElementType)(node == null ? null : node.TextElement); } return firstChild; } } ////// Returns a first item of this collection /// internal TextElementType LastChild { get { TextElementType lastChild; if (this.Parent is TextElement) { lastChild = (TextElementType)((TextElement)this.Parent).LastChildElement; } else { TextTreeTextElementNode node = this.TextContainer.LastContainedNode as TextTreeTextElementNode; lastChild = (TextElementType)(node == null ? null : node.TextElement); } return lastChild; } } #endregion Internal Properties //------------------------------------------------------------------- // // Private Methods // //-------------------------------------------------------------------- #region Private Methods // Worker for IList.RemoveAt and IList.set_Item. // Returns the element following the element removed. private TextElementType RemoveAtInternal(int index) { if (index < 0) { throw new IndexOutOfRangeException(SR.Get(SRID.TextElementCollection_IndexOutOfRange)); } TextElementType element = GetElementAtIndex(index); if (element == null) { throw new IndexOutOfRangeException(SR.Get(SRID.TextElementCollection_IndexOutOfRange)); } TextElementType nextElement = (TextElementType)element.NextElement; // Note: We need to remember the textcontainer for any delete operations in this collection. // This is important for the case when the owner of the collection is a sibling member. // In a scenario where you remove the owner itself from the collection, // the owner belongs to another tree after the reposition. TextContainer textContainer = this.TextContainer; textContainer.BeginChange(); try { // Prepare to reset the cache. // We're about to remove the current cache, so we need to find a neighbor. TextElementType newElementCache = nextElement; if (newElementCache == null) { newElementCache = (TextElementType)element.PreviousElement; index--; } // Remove the element. element.RepositionWithContent(null); // Reset the cache. if (newElementCache != null) { SetCache(index, newElementCache); } } finally { textContainer.EndChange(); } return nextElement; } // Returns an element at a given index, or null if the index is out of range. private TextElementType GetElementAtIndex(int index) { bool atCollectionEnd; return GetElementAtIndex(index, out atCollectionEnd); } // Returns an element at a given index, or null if the index is out of range. // If the index exactly equals the collection count (and hence the return value // is null), atCollectionEnd is set true. private TextElementType GetElementAtIndex(int index, out bool atCollectionEnd) { TextElementType element; bool forward = true; if (_indexCache.IsValid(this)) { if (_indexCache.Index == index) { element = _indexCache.Element; index = 0; } else if (_indexCache.Index < index) { element = _indexCache.Element; index = index - _indexCache.Index; } else // _indexCache.Index > index { element = _indexCache.Element; index = _indexCache.Index - index; forward = false; } } else { element = this.FirstChild; } while (index > 0 && element != null) { element = (TextElementType)(forward ? element.NextElement : element.PreviousElement); index--; } atCollectionEnd = (index == 0 && element == null); return element; } // Sets the element/index cache. private void SetCache(int index, TextElementType item) { _indexCache = new ElementIndexCache(index, item); TextElementCollectionHelper.MarkClean(this.Parent, this); } // Returns the index of an object in the collection, or -1 if the // object is not a member. // // If isCacheSafePreviousIndex is true, the cache is guaranteed to be // a valid index/element pair of a preceding element, regardless of // whether or not _idexCache.IsValid is true. private int IndexOfInternal(object value, bool isCacheSafePreviousIndex) { TextElementType item = value as TextElementType; if (value == null) { return -1; } // Early out on a cache hit. if (_indexCache.IsValid(this)) { if ((object)item == (object)_indexCache.Element) { return _indexCache.Index; } } int index; TextElementType element; if (isCacheSafePreviousIndex) { index = _indexCache.Index; element = _indexCache.Element; } else { index = 0; element = this.FirstChild; } while (element != null) { if (element == item) { SetCache(index, item); return index; } element = (TextElementType)element.NextElement; index++; } return -1; } #endregion Private Methods //------------------------------------------------------------------- // // Internal Methods // //------------------------------------------------------------------- #region Internal Methods ////// This method validates a child of this collection. /// Default implementation does nothing as TextElementType is a valid child type. /// InlineCollection overrides this method to do additional schema validation for its children. /// internal virtual void ValidateChild(TextElementType child) { return; } #endregion //------------------------------------------------------------------- // // Private Properties // //-------------------------------------------------------------------- #region Private Properties ////// private TextPointer ContentStart { get { return this.Parent is TextElement ? ((TextElement)this.Parent).ContentStart : this.TextContainer.Start; } } ////// private TextPointer ContentEnd { get { return this.Parent is TextElement ? ((TextElement)this.Parent).ContentEnd : this.TextContainer.End; } } #endregion Private Properties //------------------------------------------------------------------- // // Private Types // //-------------------------------------------------------------------- #region Private Types // A cached TextElementType/index pair. // Used to speed up IList calls with locality. private struct ElementIndexCache { internal ElementIndexCache(int index, TextElementType element) { // index == -1/element == null means "empty". Invariant.Assert(index == -1 || element != null); _index = index; _element = element; } // True if the cache is reliable. Otherwise, the tree has been // modified and it is not possible to guarantee a valid cache. internal bool IsValid(TextElementCollectioncollection) { return _index >= 0 && TextElementCollectionHelper.IsCleanParent(_element.Parent, collection); } // Cached element index in this collection. internal int Index { get { return _index; } } // Cached element in this collection. internal TextElementType Element { get { return _element; } } // Cached element index in this collection. private readonly int _index; // Cached element in this collection. private readonly TextElementType _element; } #endregion Private Types //-------------------------------------------------------------------- // // Private Fields // //------------------------------------------------------------------- #region Private Fields // Object associated with this collection -- its children or siblings are the collection members. private DependencyObject _owner; // Flag indicating if owner is a parent of objects in this collection or is a sibling object. private bool _isOwnerParent; // Cached element/index pair used to speed up IList calls. private ElementIndexCache _indexCache; #endregion Private Fields } } // 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
- ModelItemCollectionImpl.cs
- ListenerElementsCollection.cs
- TerminatorSinks.cs
- DateTimeConverter.cs
- Run.cs
- MessageVersion.cs
- FontUnit.cs
- ProviderUtil.cs
- ListViewTableRow.cs
- SubpageParaClient.cs
- WebServiceData.cs
- CaseInsensitiveHashCodeProvider.cs
- XPathNodeHelper.cs
- DragDrop.cs
- TypeUtils.cs
- UnsettableComboBox.cs
- HtmlInputControl.cs
- UnsafeNativeMethods.cs
- RotationValidation.cs
- XmlText.cs
- Size.cs
- ArithmeticException.cs
- UserPreferenceChangedEventArgs.cs
- BinaryConverter.cs
- DataSourceComponent.cs
- Inline.cs
- SudsCommon.cs
- EmbeddedMailObject.cs
- MenuCommandService.cs
- WsatServiceAddress.cs
- MemoryMappedFileSecurity.cs
- StylusPointProperty.cs
- UInt32Storage.cs
- _UncName.cs
- InvalidDataException.cs
- PageThemeBuildProvider.cs
- MDIControlStrip.cs
- LocalizableResourceBuilder.cs
- UrlPath.cs
- DragEvent.cs
- BitmapPalette.cs
- ServiceHandle.cs
- TypeInfo.cs
- TileBrush.cs
- Part.cs
- DispatcherTimer.cs
- BitConverter.cs
- FamilyMapCollection.cs
- ConnectionProviderAttribute.cs
- MachineKeySection.cs
- TargetConverter.cs
- CachedRequestParams.cs
- SecurityTokenContainer.cs
- TextRenderer.cs
- GroupQuery.cs
- IIS7WorkerRequest.cs
- MediaElement.cs
- EditorServiceContext.cs
- InstanceNameConverter.cs
- LineProperties.cs
- CodeArgumentReferenceExpression.cs
- BevelBitmapEffect.cs
- FrameworkTemplate.cs
- MaterialGroup.cs
- MetadataCache.cs
- RoutingExtensionElement.cs
- MonthCalendarDesigner.cs
- AppDomainInfo.cs
- SoapSchemaMember.cs
- TreeViewHitTestInfo.cs
- WhitespaceRuleReader.cs
- TabControlAutomationPeer.cs
- _ProxyChain.cs
- ObjectAnimationBase.cs
- Clause.cs
- XmlEntityReference.cs
- AvtEvent.cs
- Operator.cs
- HwndStylusInputProvider.cs
- SendingRequestEventArgs.cs
- KeyInterop.cs
- WebSysDefaultValueAttribute.cs
- CultureSpecificCharacterBufferRange.cs
- ConfigXmlWhitespace.cs
- PeerNearMe.cs
- SiteMapPath.cs
- ExtenderControl.cs
- LOSFormatter.cs
- DecimalKeyFrameCollection.cs
- ProcessModuleCollection.cs
- SiteMapHierarchicalDataSourceView.cs
- TargetConverter.cs
- SerialPort.cs
- ChangeDirector.cs
- OleDbMetaDataFactory.cs
- WebServiceMethodData.cs
- Color.cs
- DesignerSerializationVisibilityAttribute.cs
- SemanticResultValue.cs
- TypeUnloadedException.cs