Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / System / Windows / Media / VisualCollection.cs / 2 / VisualCollection.cs
//------------------------------------------------------------------------------ // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // The VisualCollection implementation is based on the // CLR's Lightning ArrayList implementation. // //----------------------------------------------------------------------------- using MS.Win32; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Composition; using System.Windows.Threading; using System; using System.Diagnostics; using System.Collections; using MS.Internal; using System.Runtime.InteropServices; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; //----------------------------------------------------------------------------- // Todo: // - Bug: There is an exception thrown inside of ConnectChild which could render // the collection inconsistent. // - Performance: RemoveRange moves and nulls entry. It is better to null out // after we moved all the items. //----------------------------------------------------------------------------- // Since we disable PreSharp warnings in this file, we first need to disable // warnings about unknown message numbers and unknown pragmas: #pragma warning disable 1634, 1691 namespace System.Windows.Media { ////// A VisualCollection is a ordered collection of Visuals. /// ////// A VisualCollection has implied context affinity. It is a violation to access /// the VisualCollectionfrom a different context than the owning ContainerVisual belongs /// to. /// public sealed class VisualCollection : ICollection { private Visual[] _items; private int _size; private Visual _owner; // We reserve bit 1 to keep track of readonly state. Bits // 32..2 are used for our version counter. // // Version RO // +----------------------------------+---+ // | bit 32..2 | 1 | // +----------------------------------+---+ // private uint _data; private const int c_defaultCapacity = 4; private const float c_growFactor = 1.5f; internal int InternalCount { get { return _size; } } ////// Returns a reference to the internal Visual children array. /// ////// This array should never given out. /// It is only used for internal code /// to enumerate through the children. /// internal Visual[] InternalArray { get { return _items; } } ////// Creates a VisualCollection. /// public VisualCollection(Visual parent) { if (parent == null) { throw new ArgumentNullException("parent"); } _owner = parent; } internal void VerifyAPIReadOnly() { Debug.Assert(_owner != null); _owner.VerifyAPIReadOnly(); } internal void VerifyAPIReadOnly(Visual other) { Debug.Assert(_owner != null); _owner.VerifyAPIReadOnly(other); } internal void VerifyAPIReadWrite() { Debug.Assert(_owner != null); _owner.VerifyAPIReadWrite(); VerifyNotReadOnly(); } internal void VerifyAPIReadWrite(Visual other) { Debug.Assert(_owner != null); _owner.VerifyAPIReadWrite(other); VerifyNotReadOnly(); } internal void VerifyNotReadOnly() { if (IsReadOnlyInternal) { throw new InvalidOperationException(SR.Get(SRID.VisualCollection_ReadOnly)); } } ////// Gets the number of elements in the collection. /// public int Count { get { VerifyAPIReadOnly(); return InternalCount; } } ////// True if the collection allows modifications, otherwise false. /// public bool IsReadOnly { get { VerifyAPIReadOnly(); return IsReadOnlyInternal; } } ////// Gets a value indicating whether access to the ICollection /// is synchronized (thread-safe). /// public bool IsSynchronized { get { VerifyAPIReadOnly(); return false; } } ////// Gets an object that can be used to synchronize access /// to the ICollection. /// /// ??? Figure out what we need to return here. We do have context /// affinity which renders this property useless. /// /// ArrayList returns "this". I am still not sure what this is /// used for. Check! /// public object SyncRoot { get { VerifyAPIReadOnly(); return this; } } ////// Copies the Visual collection to the specified array starting at the specified index. /// public void CopyTo(Array array, int index) { VerifyAPIReadOnly(); if (array == null) { throw new ArgumentNullException("array"); } if (array.Rank != 1) { throw new ArgumentException(SR.Get(SRID.Collection_BadRank)); } if ((index < 0) || (array.Length - index < _size)) { throw new ArgumentOutOfRangeException("index"); } // System.Array does not have a CopyTo method that takes a count. Therefore // the loop is programmed here out. for (int i=0; i < _size; i++) { array.SetValue(_items[i], i+index); } } ////// Copies the Visual collection to the specified array starting at the specified index. /// public void CopyTo(Visual[] array, int index) { // Remark: This is the strongly typed version of the ICollection.CopyTo method. // FXCop requires us to implement this method. VerifyAPIReadOnly(); if (array == null) { throw new ArgumentNullException("array"); } if ((index < 0) || (array.Length - index < _size)) { throw new ArgumentOutOfRangeException("index"); } // System.Array does not have a CopyTo method that takes a count. Therefore // the loop is programmed here out. for (int i=0; i < _size; i++) { array[i+index] = _items[i]; } } // ---------------------------------------------------------------- // ArrayList like operations for the VisualCollection // --------------------------------------------------------------- ////// Ensures that the capacity of this list is at least the given minimum /// value. If the currect capacity of the list is less than min, the /// capacity is increased to min. /// private void EnsureCapacity(int min) { if (InternalCapacity < min) { InternalCapacity = Math.Max(min, (int)(InternalCapacity * c_growFactor)); } } ////// InternalCapacity sets/gets the Capacity of the collection. /// internal int InternalCapacity { get { return _items != null ? _items.Length : 0; } set { int currentCapacity = _items != null ? _items.Length : 0; if (value != currentCapacity) { if (value < _size) { throw new ArgumentOutOfRangeException("value", SR.Get(SRID.VisualCollection_NotEnoughCapacity)); } if (value > 0) { Visual[] newItems = new Visual[value]; if (_size > 0) { Debug.Assert(_items != null); Array.Copy(_items, 0, newItems, 0, _size); } _items = newItems; } else { Debug.Assert(value == 0, "There shouldn't be a case where value != 0."); Debug.Assert(_size == 0, "Size must be 0 here."); _items = null; } } } } ////// Gets or sets the number of elements that the VisualCollection can contain. /// ////// The number of elements that the VisualCollection can contain. /// ////// Capacity is the number of elements that the VisualCollection is capable of storing. /// Count is the number of Visuals that are actually in the VisualCollection. /// /// Capacity is always greater than or equal to Count. If Count exceeds /// Capacity while adding elements, the capacity of the VisualCollection is increased. /// /// By default the capacity is 0. /// ///Capacity is set to a value that is less than Count. public int Capacity { get { VerifyAPIReadOnly(); return InternalCapacity; } set { VerifyAPIReadWrite(); InternalCapacity = value; } } ////// Indexer for the VisualCollection. Gets or sets the Visual stored at the /// zero-based index of the VisualCollection. /// ///This property provides the ability to access a specific Visual in the /// VisualCollection by using the following systax: ///myVisualCollection[index] ./// index is less than zero -or-index is equal to or greater than Count.If the new child has already a parent or if the slot a the specified index is not null. public Visual this[int index] { get { // ([....]) I think we should skip the context checks here for performance reasons. // MediaSystem.VerifyContext(_owner); The guy who gets the Visual won't be able to access the context // the Visual anyway if he is in the wrong context. // Disable PREsharp warning about throwing exceptions in property // get methods; see Windows OS Bugs #1035349 for an explanation. #pragma warning disable 6503 if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException("index"); return _items[index]; #pragma warning restore 6503 } set { VerifyAPIReadWrite(value); if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException("index"); Visual child = _items[index]; if ((value == null) && (child != null)) { DisconnectChild(index); } else if (value != null) { if (child != null) { throw new System.ArgumentException(SR.Get(SRID.VisualCollection_EntryInUse)); } if ((value._parent != null) // Only a visual that isn't a visual parent or || value.IsRootElement) // are a root node of a visual target can be set into the collection. { throw new System.ArgumentException(SR.Get(SRID.VisualCollection_VisualHasParent)); } ConnectChild(index, value); } } } ////// Sets the specified visual at the specified index into the child /// collection. It also corrects the parent. /// Note that the function requires that _item[index] == null and it /// also requires that the passed in child is not connected to another Visual. /// ///If the new child has already a parent or if the slot a the specified index is not null. private void ConnectChild(int index, Visual value) { // // -- Approved By The Core Team -- // // Do not allow foreign threads to change the tree. // (This is a noop if this object is not assigned to a Dispatcher.) // // We also need to ensure that the tree is homogenous with respect // to the dispatchers that the elements belong to. // _owner.VerifyAccess(); value.VerifyAccess(); // It is invalid to modify the children collection that we // might be iterating during a property invalidation tree walk. if (_owner.IsVisualChildrenIterationInProgress) { throw new InvalidOperationException(SR.Get(SRID.CannotModifyVisualChildrenDuringTreeWalk)); } Debug.Assert(value != null); Debug.Assert(_items[index] == null); Debug.Assert(value._parent == null); Debug.Assert(!value.IsRootElement); value._parentIndex = index; _items[index] = value; IncrementVersion(); // Notify the Visual tree about the children changes. _owner.InternalAddVisualChild(value); } ////// Disconnects a child. /// private void DisconnectChild(int index) { Debug.Assert(_items[index] != null); Visual child = _items[index]; // // -- Approved By The Core Team -- // // Do not allow foreign threads to change the tree. // (This is a noop if this object is not assigned to a Dispatcher.) // child.VerifyAccess(); Visual oldParent = VisualTreeHelper.GetContainingVisual2D(child._parent); int oldParentIndex = child._parentIndex; // It is invalid to modify the children collection that we // might be iterating during a property invalidation tree walk. if (oldParent.IsVisualChildrenIterationInProgress) { throw new InvalidOperationException(SR.Get(SRID.CannotModifyVisualChildrenDuringTreeWalk)); } _items[index] = null; #if DEBUG child._parentIndex = -1; #endif IncrementVersion(); _owner.InternalRemoveVisualChild(child); } ////// Appends a Visual to the end of the VisualCollection. /// /// The Visual to be added to the end of the VisualCollection. ///The VisualCollection index at which the Visual has been added. ///Adding a null is allowed. ///If the new child has already a parent. public int Add(Visual visual) { VerifyAPIReadWrite(visual); if ((visual != null) && ((visual._parent != null) // Only visuals that are not connected to another tree || visual.IsRootElement)) // or a visual target can be added. { throw new System.ArgumentException(SR.Get(SRID.VisualCollection_VisualHasParent)); } if ((_items == null) || (_size == _items.Length)) { EnsureCapacity(_size+1); } int addedPosition = _size++; Debug.Assert(_items[addedPosition] == null); if (visual != null) { ConnectChild(addedPosition, visual); } IncrementVersion(); return addedPosition; } ////// Returns the zero-based index of the Visual. If the Visual is not /// in the VisualCollection -1 is returned. If null is passed to the method, the index /// of the first entry with null is returned. If there is no null entry -1 is returned. /// /// The Visual to locate in the VisualCollection. ///Runtime of this method is constant if the argument is not null. If the argument is /// null, the runtime of this method is linear in the size of the collection. /// public int IndexOf(Visual visual) { VerifyAPIReadOnly(); if (visual == null) { // If the passed in argument is null, we find the first index with a null // entry and return it. for (int i = 0; i < _size; i++) { if (_items[i] == null) { return i; } } // No null entry found, return -1. return -1; } else if (visual._parent != _owner) { return -1; } else { return visual._parentIndex; } } ////// Removes the specified visual from the VisualCollection. /// /// The Visual to remove from the VisualCollection. ////// The Visuals that follow the removed Visuals move up to occupy /// the vacated spot. The indexes of the Visuals that are moved are /// also updated. /// /// If visual is null then the first null entry is removed. Note that removing /// a null entry is linear in the size of the collection. /// public void Remove(Visual visual) { VerifyAPIReadWrite(visual); InternalRemove(visual); } private void InternalRemove(Visual visual) { int indexToRemove = -1; if (visual != null) { if (visual._parent != _owner) { // If the Visual is not in this collection we silently return without // failing. This is the same behavior that ArrayList implements. See // also Windows OS Bug #1100006. return; } Debug.Assert(visual._parent != null); indexToRemove = visual._parentIndex; DisconnectChild(indexToRemove); } else { // This is the case where visual == null. We then remove the first null // entry. for (int i = 0; i < _size; i++) { if (_items[i] == null) { indexToRemove = i; break; } } } if (indexToRemove != -1) { --_size; for (int i = indexToRemove; i < _size; i++) { Visual child = _items[i+1]; if (child != null) { child._parentIndex = i; } _items[i] = child; } _items[_size] = null; } } private uint Version { get { // >> 1 because bit 1 is our read-only flag. See comments // on the _data field. return _data >> 1; } } private void IncrementVersion() { // += 2 because bit 1 is our read-only flag. Explicitly unchecked // because we expect this number to "roll over" after 2 billion calls. // See comments on _data field. unchecked { _data += 2; } } private bool IsReadOnlyInternal { get { // Bit 1 is our read-only flag. See comments on the _data field. return (_data & 0x01) == 0x01; } } // Puts the collection into a ReadOnly state. Viewport3DVisual does this // on construction to prevent the addition of 2D children. internal void SetReadOnly() { // Bit 1 is our read-only flag. See comments on the _data field. _data |= 0x01; } ////// Determines whether a visual is in the VisualCollection. /// public bool Contains(Visual visual) { VerifyAPIReadOnly(visual); if (visual == null) { for (int i=0; i < _size; i++) { if (_items[i] == null) { return true; } } return false; } else { return (visual._parent == _owner); } } ////// Removes all elements from the VisualCollection. /// ////// Count is set to zero. Capacity remains unchanged. /// To reset the capacity of the VisualCollection, /// set the Capacity property directly. /// public void Clear() { VerifyAPIReadWrite(); for (int i=0; i < _size; i++) { if (_items[i] != null) { Debug.Assert(_items[i]._parent == _owner); DisconnectChild(i); } _items[i] = null; } _size = 0; IncrementVersion(); } ////// Inserts an element into the VisualCollection at the specified index. /// /// The zero-based index at which value should be inserted. /// The Visual to insert. ////// index is less than zero. /// /// -or- /// /// index is greater than Count. /// ////// If Count already equals Capacity, the capacity of the /// VisualCollection is increased before the new Visual /// is inserted. /// /// If index is equal to Count, value is added to the /// end of VisualCollection. /// /// The Visuals that follow the insertion point move down to /// accommodate the new Visual. The indexes of the Visuals that are /// moved are also updated. /// public void Insert(int index, Visual visual) { VerifyAPIReadWrite(visual); if (index < 0 || index > _size) { throw new ArgumentOutOfRangeException("index"); } if ((visual != null) && ((visual._parent != null) // Only visuals that are not connected to another tree || visual.IsRootElement)) // or a visual target can be added. { throw new System.ArgumentException(SR.Get(SRID.VisualCollection_VisualHasParent)); } if ((_items == null) || (_size == _items.Length)) { EnsureCapacity(_size + 1); } for (int i = _size-1; i >= index; i--) { Visual child = _items[i]; if (child != null) { child._parentIndex = i+1; } _items[i+1] = child; } _items[index] = null; _size++; if (visual != null) { ConnectChild(index, visual); } // Note SetVisual that increments the version to ensure proper enumerator // functionality. } ////// Removes the Visual at the specified index. /// /// The zero-based index of the visual to remove. ///index is less than zero /// - or - index is equal or greater than count. ////// The Visuals that follow the removed Visuals move up to occupy /// the vacated spot. The indexes of the Visuals that are moved are /// also updated. /// public void RemoveAt(int index) { VerifyAPIReadWrite(); if (index < 0 || index >= _size) { throw new ArgumentOutOfRangeException("index"); } InternalRemove(_items[index]); } ////// Removes a range of Visuals from the VisualCollection. /// /// The zero-based index of the range /// of elements to remove /// The number of elements to remove. ////// index is less than zero. /// -or- /// count is less than zero. /// ////// index and count do not denote a valid range of elements in the VisualCollection. /// ////// The Visuals that follow the removed Visuals move up to occupy /// the vacated spot. The indexes of the Visuals that are moved are /// also updated. /// public void RemoveRange(int index, int count) { VerifyAPIReadWrite(); // ([....]) Do I need this extra check index >= _size. if (index < 0) { throw new ArgumentOutOfRangeException("index"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if (_size - index < count) { throw new ArgumentOutOfRangeException("index"); } if (count > 0) { for (int i = index; i < index + count; i++) { if (_items[i] != null) { DisconnectChild(i); _items[i] = null; } } _size -= count; for (int i = index; i < _size; i++) { Visual child = _items[i + count]; if (child != null) { child._parentIndex = i; } _items[i] = child; _items[i + count] = null; } IncrementVersion(); // Incrementing version number here to be consistent with the ArrayList // implementation. } } // ---------------------------------------------------------------- // IEnumerable Interface // ---------------------------------------------------------------- ////// Returns an enumerator that can iterate through the VisualCollection. /// ///Enumerator that enumerates the VisualCollection in order. IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } ////// Returns an enumerator that can iterate through the VisualCollection. /// ///Enumerator that enumerates the VisualCollection in order. public Enumerator GetEnumerator() { VerifyAPIReadOnly(); return new Enumerator(this); } ////// This is a simple VisualCollection enumerator that is based on /// the ArrayListEnumeratorSimple that is used for ArrayLists. /// /// The following comment is from the CLR people: /// For a straightforward enumeration of the entire ArrayList, /// this is faster, because it's smaller. Benchmarks showed /// this. /// public struct Enumerator : IEnumerator { private VisualCollection _collection; private int _index; // -1 means not started. -2 means that it reached the end. private uint _version; private Visual _currentElement; internal Enumerator(VisualCollection collection) { _collection = collection; _index = -1; // not started. _version = _collection.Version; _currentElement = null; } ////// Advances the enumerator to the next element of the collection. /// public bool MoveNext() { _collection.VerifyAPIReadOnly(); if (_version == _collection.Version) { if ((_index > -2) && (_index < (_collection.InternalCount - 1))) { _index++; _currentElement = _collection[_index]; return true; } else { _currentElement = null; _index = -2; // -2 <=> reached the end. return false; } } else { throw new InvalidOperationException(SR.Get(SRID.Enumerator_CollectionChanged)); } } ////// Gets the current Visual. /// object IEnumerator.Current { get { return this.Current; } } ////// Gets the current Visual. /// public Visual Current { get { // Disable PREsharp warning about throwing exceptions in property // get methods; see Windows OS Bugs #1035349 for an explanation. #pragma warning disable 6503 if (_index < 0) { if (_index == -1) { // Not started. throw new InvalidOperationException(SR.Get(SRID.Enumerator_NotStarted)); } else { // Reached the end. Debug.Assert(_index == -2); throw new InvalidOperationException(SR.Get(SRID.Enumerator_ReachedEnd)); } } return _currentElement; #pragma warning restore 6503 } } ////// Sets the enumerator to its initial position, which is before the first element in the collection. /// public void Reset() { _collection.VerifyAPIReadOnly(); if (_version != _collection.Version) throw new InvalidOperationException(SR.Get(SRID.Enumerator_CollectionChanged)); _index = -1; // not started. } } } } // 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
- CroppedBitmap.cs
- DrawingContextDrawingContextWalker.cs
- BindingContext.cs
- FacetDescription.cs
- LineSegment.cs
- ControlUtil.cs
- Image.cs
- Statements.cs
- TableProvider.cs
- ReadOnlyAttribute.cs
- SecurityTokenTypes.cs
- SqlCommand.cs
- SqlDataSource.cs
- GridItemProviderWrapper.cs
- StylusPointProperty.cs
- MasterPageParser.cs
- ResourceDisplayNameAttribute.cs
- SHA1.cs
- RadioButtonRenderer.cs
- TrackingMemoryStreamFactory.cs
- PersistenceProviderElement.cs
- HostedHttpContext.cs
- RetrieveVirtualItemEventArgs.cs
- NamedElement.cs
- ExcludePathInfo.cs
- SortKey.cs
- MULTI_QI.cs
- PersonalizableAttribute.cs
- ViewKeyConstraint.cs
- CollectionChangeEventArgs.cs
- ObfuscateAssemblyAttribute.cs
- GlobalizationAssembly.cs
- _BufferOffsetSize.cs
- NaturalLanguageHyphenator.cs
- SortExpressionBuilder.cs
- LinqDataSourceValidationException.cs
- RandomNumberGenerator.cs
- ParsedAttributeCollection.cs
- CodeConditionStatement.cs
- ObjectQueryState.cs
- XmlProcessingInstruction.cs
- PolyLineSegmentFigureLogic.cs
- SizeKeyFrameCollection.cs
- HtmlLink.cs
- PageRanges.cs
- GlyphTypeface.cs
- RemotingAttributes.cs
- CommandDesigner.cs
- DiagnosticSection.cs
- ToolStripPanelCell.cs
- SqlNodeAnnotations.cs
- ReverseInheritProperty.cs
- ConfigurationManagerInternalFactory.cs
- StdValidatorsAndConverters.cs
- InvalidOleVariantTypeException.cs
- StrokeNodeEnumerator.cs
- ListBoxAutomationPeer.cs
- ComplusEndpointConfigContainer.cs
- ProcessManager.cs
- Formatter.cs
- Rotation3DKeyFrameCollection.cs
- DescendantOverDescendantQuery.cs
- InputLanguageEventArgs.cs
- DataErrorValidationRule.cs
- PolicyDesigner.cs
- Int64AnimationUsingKeyFrames.cs
- ObjectListCommandCollection.cs
- PropertyMetadata.cs
- PassportIdentity.cs
- WindowsEditBox.cs
- SqlFunctionAttribute.cs
- WindowsFormsHelpers.cs
- GenericRootAutomationPeer.cs
- DateTimeConverter2.cs
- UnauthorizedWebPart.cs
- FigureHelper.cs
- RadioButtonList.cs
- ErasingStroke.cs
- CodeAccessPermission.cs
- WizardStepBase.cs
- BevelBitmapEffect.cs
- MetafileHeaderWmf.cs
- WebConfigurationHost.cs
- PersonalizationStateInfo.cs
- BitVec.cs
- DirtyTextRange.cs
- CodeGroup.cs
- TemplatePartAttribute.cs
- QilValidationVisitor.cs
- WindowsGrip.cs
- RemotingServices.cs
- UnsignedPublishLicense.cs
- InstanceView.cs
- ConstraintConverter.cs
- ThreadAbortException.cs
- KnownTypeHelper.cs
- StaticExtension.cs
- TextBox.cs
- TextTreeExtractElementUndoUnit.cs
- CacheChildrenQuery.cs