Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / Media / VisualCollection.cs / 1305600 / 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. } } ////// 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
- Win32MouseDevice.cs
- SiteMapDataSource.cs
- DataRowView.cs
- TemplatePropertyEntry.cs
- XPathScanner.cs
- VirtualizingStackPanel.cs
- NavigationPropertyEmitter.cs
- SpeechEvent.cs
- VersionPair.cs
- TypeSystemProvider.cs
- PageThemeCodeDomTreeGenerator.cs
- DataGridViewToolTip.cs
- LZCodec.cs
- ValidationError.cs
- XmlILModule.cs
- SBCSCodePageEncoding.cs
- BinaryParser.cs
- Pen.cs
- UnsafeNativeMethods.cs
- StructuralObject.cs
- AutomationPeer.cs
- PopupControlService.cs
- UpdatePanel.cs
- XsdValidatingReader.cs
- UnionCodeGroup.cs
- ProfileBuildProvider.cs
- OrderedDictionary.cs
- InstancePersistence.cs
- MemberInfoSerializationHolder.cs
- ToolStripGrip.cs
- WebConfigurationManager.cs
- TextUtf8RawTextWriter.cs
- LayoutEvent.cs
- BasePropertyDescriptor.cs
- LogRestartAreaEnumerator.cs
- Table.cs
- HttpFileCollection.cs
- DesignTimeVisibleAttribute.cs
- ResourceReferenceKeyNotFoundException.cs
- DataControlCommands.cs
- OutOfProcStateClientManager.cs
- EventProvider.cs
- KeyEvent.cs
- Command.cs
- ListBox.cs
- StickyNoteHelper.cs
- SqlDataSourceEnumerator.cs
- GridViewColumnHeader.cs
- KeyTimeConverter.cs
- Screen.cs
- TimeoutValidationAttribute.cs
- XhtmlTextWriter.cs
- CqlIdentifiers.cs
- RepeaterItem.cs
- LocatorGroup.cs
- TextEditorThreadLocalStore.cs
- XmlIncludeAttribute.cs
- CompareValidator.cs
- SystemColorTracker.cs
- RouteItem.cs
- XMLSchema.cs
- Visual3D.cs
- ApplicationSecurityInfo.cs
- ReceiveSecurityHeaderElementManager.cs
- PaginationProgressEventArgs.cs
- TrackingMemoryStreamFactory.cs
- DbDataSourceEnumerator.cs
- RegexCaptureCollection.cs
- RewritingSimplifier.cs
- WorkflowMarkupSerializationException.cs
- DataMemberConverter.cs
- TextAction.cs
- FixedBufferAttribute.cs
- ThaiBuddhistCalendar.cs
- CancelEventArgs.cs
- TemplateContainer.cs
- TreeViewDesigner.cs
- _NetworkingPerfCounters.cs
- BitmapEffectGroup.cs
- SafeFileHandle.cs
- ArcSegment.cs
- panel.cs
- InvalidOperationException.cs
- StaticFileHandler.cs
- CheckedListBox.cs
- ProfileSettingsCollection.cs
- Int32CollectionValueSerializer.cs
- ToolStripSystemRenderer.cs
- IsolatedStorage.cs
- Scalars.cs
- CodeTypeParameterCollection.cs
- DependencyPropertyChangedEventArgs.cs
- WebControl.cs
- PeerUnsafeNativeMethods.cs
- ListItemConverter.cs
- FrugalList.cs
- HostedElements.cs
- UpdateException.cs
- UTF32Encoding.cs
- InvokeMemberBinder.cs