Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Core / CSharp / System / Windows / Media / VisualCollection.cs / 1 / 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 { // (Gschneid) 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(); // (GSchneid) 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. } } ////// Moves a child inside this collection to right before the given sibling. Avoids unparenting / reparenting costs. /// This is a dangerous internal method as it moves children positions without notifying any external code. /// If the given sibling is null it moves the item to the end of the collection. /// /// /// internal void Move(Visual visual, Visual destination) { int newIndex; int oldIndex; Invariant.Assert(visual != null, "we don't support moving a null visual"); if (visual._parent == _owner) { oldIndex = visual._parentIndex; newIndex = destination != null ? destination._parentIndex : _size; Debug.Assert(visual._parent != null); Debug.Assert(destination == null || destination._parent == visual._parent); Debug.Assert(newIndex >= 0 && newIndex <= _size, "New index is invalid"); if (oldIndex != newIndex) { if (oldIndex < newIndex) { // move items left to right // source Visual will get the index of one before the destination Visual newIndex--; for (int i = oldIndex; i < newIndex; i++) { Visual child = _items[i + 1]; if (child != null) { child._parentIndex = i; } _items[i] = child; } } else { // move items right to left // source visual will get the index of the destination Visual, which will in turn // be pushed to the right. for (int i = oldIndex; i > newIndex; i--) { Visual child = _items[i - 1]; if (child != null) { child._parentIndex = i; } _items[i] = child; } } visual._parentIndex = newIndex; _items[newIndex] = visual; } } return; } // ---------------------------------------------------------------- // 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. //------------------------------------------------------------------------------ // //// 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 { // (Gschneid) 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(); // (GSchneid) 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. } } ////// Moves a child inside this collection to right before the given sibling. Avoids unparenting / reparenting costs. /// This is a dangerous internal method as it moves children positions without notifying any external code. /// If the given sibling is null it moves the item to the end of the collection. /// /// /// internal void Move(Visual visual, Visual destination) { int newIndex; int oldIndex; Invariant.Assert(visual != null, "we don't support moving a null visual"); if (visual._parent == _owner) { oldIndex = visual._parentIndex; newIndex = destination != null ? destination._parentIndex : _size; Debug.Assert(visual._parent != null); Debug.Assert(destination == null || destination._parent == visual._parent); Debug.Assert(newIndex >= 0 && newIndex <= _size, "New index is invalid"); if (oldIndex != newIndex) { if (oldIndex < newIndex) { // move items left to right // source Visual will get the index of one before the destination Visual newIndex--; for (int i = oldIndex; i < newIndex; i++) { Visual child = _items[i + 1]; if (child != null) { child._parentIndex = i; } _items[i] = child; } } else { // move items right to left // source visual will get the index of the destination Visual, which will in turn // be pushed to the right. for (int i = oldIndex; i > newIndex; i--) { Visual child = _items[i - 1]; if (child != null) { child._parentIndex = i; } _items[i] = child; } } visual._parentIndex = newIndex; _items[newIndex] = visual; } } return; } // ---------------------------------------------------------------- // 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
- LocalizationComments.cs
- SchemaName.cs
- _Rfc2616CacheValidators.cs
- SortExpressionBuilder.cs
- CompilerErrorCollection.cs
- SimpleBitVector32.cs
- InvalidComObjectException.cs
- ValueExpressions.cs
- storepermissionattribute.cs
- BinarySecretKeyIdentifierClause.cs
- DmlSqlGenerator.cs
- SqlFactory.cs
- documentsequencetextpointer.cs
- StringUtil.cs
- SafeEventLogReadHandle.cs
- Baml2006ReaderContext.cs
- DbConnectionFactory.cs
- TableItemPatternIdentifiers.cs
- Empty.cs
- MULTI_QI.cs
- AsymmetricSecurityBindingElement.cs
- BrowserDefinition.cs
- TextRunCache.cs
- XmlTextReaderImpl.cs
- WebZone.cs
- XmlAutoDetectWriter.cs
- ClientTargetCollection.cs
- XmlSerializerSection.cs
- PropertyContainer.cs
- MissingSatelliteAssemblyException.cs
- X509CertificateTokenFactoryCredential.cs
- CodeDOMProvider.cs
- IListConverters.cs
- WeakEventManager.cs
- unsafenativemethodsother.cs
- TextParaLineResult.cs
- XsltLoader.cs
- documentsequencetextpointer.cs
- ChannelFactory.cs
- ResourceAttributes.cs
- MouseEventArgs.cs
- ContainerVisual.cs
- UrlPropertyAttribute.cs
- ListSortDescriptionCollection.cs
- ExpandCollapsePattern.cs
- MessageHeaders.cs
- SystemIPv4InterfaceProperties.cs
- Setter.cs
- AppLevelCompilationSectionCache.cs
- CustomValidator.cs
- ZipIOLocalFileHeader.cs
- FieldAccessException.cs
- ExtendedPropertyDescriptor.cs
- AutomationElementIdentifiers.cs
- RelationshipManager.cs
- InstanceLockedException.cs
- ValidationSummary.cs
- PreservationFileReader.cs
- CultureMapper.cs
- VarInfo.cs
- WebSysDisplayNameAttribute.cs
- CreateUserErrorEventArgs.cs
- WebPartConnectionCollection.cs
- ProtectedConfiguration.cs
- MexHttpsBindingElement.cs
- OperationCanceledException.cs
- RolePrincipal.cs
- TypeToken.cs
- BindingCollection.cs
- MimeTypePropertyAttribute.cs
- Pen.cs
- MultiView.cs
- ListView.cs
- StackOverflowException.cs
- WebSysDisplayNameAttribute.cs
- ParallelTimeline.cs
- TrustManagerMoreInformation.cs
- MessageAction.cs
- ButtonFlatAdapter.cs
- ClientRuntimeConfig.cs
- IOThreadTimer.cs
- ElapsedEventArgs.cs
- DictionarySectionHandler.cs
- DataControlLinkButton.cs
- Expr.cs
- EditorAttribute.cs
- SharedPersonalizationStateInfo.cs
- SettingsAttributeDictionary.cs
- EncoderParameter.cs
- SqlProviderServices.cs
- XmlSchemaAttribute.cs
- AppearanceEditorPart.cs
- MostlySingletonList.cs
- AudioBase.cs
- MouseButton.cs
- RenderingEventArgs.cs
- HTMLTextWriter.cs
- EditorAttribute.cs
- State.cs
- TraceContextRecord.cs