Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Controls / panel.cs / 2 / panel.cs
//---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // // File: Panel.cs // // Description: Contains the Panel base class. // Spec at http://avalon/layout/Specs/Panel.xml // // History: // 06/30/2003 : greglett - Added to WCP branch (was Stack.cs in old branch) // //--------------------------------------------------------------------------- using MS.Internal; using MS.Internal.Controls; using MS.Internal.KnownBoxes; using MS.Internal.PresentationFramework; using MS.Utility; using System.Collections; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Windows.Threading; using System.Windows.Media; using System.Windows.Markup; // IAddChild, ContentPropertyAttribute using System.Windows.Documents; using System.Windows.Controls.Primitives; // IItemContainerGenerator using System; namespace System.Windows.Controls { ////// [Localizability(LocalizationCategory.Ignore)] [ContentProperty("Children")] public abstract class Panel : FrameworkElement, IAddChild { //------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors ////// Default DependencyObject constructor /// ////// Automatic determination of current Dispatcher. Use alternative constructor /// that accepts a Dispatcher for best performance. /// protected Panel() : base() { _zConsonant = (int)ZIndexProperty.GetDefaultValue(DependencyObjectType); } ////// Initializes a new instance of a Panel. /// /// Whether the panel should support virtualization. internal Panel(bool supportsVirtualization) : base() { SetBoolField(BoolField.SupportsVirtualization, supportsVirtualization); _zConsonant = (int)ZIndexProperty.GetDefaultValue(DependencyObjectType); } ////// Static Ctor to create default style sheet. /// static Panel() { } #endregion //-------------------------------------------------------------------- // // Public Methods // //------------------------------------------------------------------- #region Public Methods ////// Override from UIElement /// protected override void OnRender(DrawingContext dc) { // Draw background in rectangle inside border. Brush background = this.Background; if (background != null) { dc.DrawRectangle(background, null, new Rect(0, 0, RenderSize.Width, RenderSize.Height)); } } ////// This method is called to Add the object as a child of the Panel. This method is used primarily /// by the parser. /// /// /// The object to add as a child; it must be a UIElement. /// ///void IAddChild.AddChild (Object value) { if (value == null) { throw new ArgumentNullException("value"); } if(IsItemsHost) { throw new InvalidOperationException(SR.Get(SRID.Panel_BoundPanel_NoChildren)); } UIElement uie = value as UIElement; if (uie == null) { throw new ArgumentException(SR.Get(SRID.UnexpectedParameterType, value.GetType(), typeof(UIElement)), "value"); } Children.Add(uie); } /// /// This method is called by the parser when text appears under the tag in markup. /// As default Panels do not support text, calling this method has no effect. /// /// /// Text to add as a child. /// void IAddChild.AddText (string text) { XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this); } #endregion //-------------------------------------------------------------------- // // Public Properties + Avalon Dependency ID's // //-------------------------------------------------------------------- #region Public Properties ////// The Background property defines the brush used to fill the area between borders. /// public Brush Background { get { return (Brush) GetValue(BackgroundProperty); } set { SetValue(BackgroundProperty, value); } } ////// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register("Background", typeof(Brush), typeof(Panel), new FrameworkPropertyMetadata((Brush)null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender)); ///property. /// /// Returns enumerator to logical children. /// protected internal override IEnumerator LogicalChildren { get { if ((this.VisualChildrenCount == 0) || IsItemsHost) { // empty panel or a panel being used as the items // host has *no* logical children; give empty enumerator return EmptyEnumerator.Instance; } // otherwise, its logical children is its visual children return this.Children.GetEnumerator(); } } ////// Returns a UIElementCollection of children for user to add/remove children manually /// Returns read-only collection if Panel is data-bound (no manual control of children is possible, /// the associated ItemsControl completely overrides children) /// Note: the derived Panel classes should never use this collection for /// internal purposes like in their MeasureOverride or ArrangeOverride. /// They should use InternalChildren instead, because InternalChildren /// is always present and either is a mirror of public Children collection (in case of Direct Panel) /// or is generated from data binding. /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public UIElementCollection Children { get { // May want to throw an InvalidOperationException if SupportsVirtualization is true //When we will change from UIElementCollection to IList, we might //consider returning a wrapper IList here which coudl be read-only for mutating methods //while INternalChildren could be R/W even in case of Generator attached. return InternalChildren; } } /// /// This method is used by TypeDescriptor to determine if this property should /// be serialized. /// // Should serialize property Children only if it is non empty [EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeChildren() { if (!IsItemsHost) { if (Children != null && Children.Count > 0) { return true; } } return false; } ////// The DependencyProperty for the IsItemsHost property. /// Flags: NotDataBindable /// Default Value: false /// public static readonly DependencyProperty IsItemsHostProperty = DependencyProperty.Register( "IsItemsHost", typeof(bool), typeof(Panel), new FrameworkPropertyMetadata( BooleanBoxes.FalseBox, // defaultValue FrameworkPropertyMetadataOptions.NotDataBindable, new PropertyChangedCallback(OnIsItemsHostChanged))); ////// IsItemsHost is set to true to indicate that the panel /// is the container for UI generated for the items of an /// ItemsControl. It is typically set in a style for an ItemsControl. /// [Bindable(false), Category("Behavior")] public bool IsItemsHost { get { return (bool) GetValue(IsItemsHostProperty); } set { SetValue(IsItemsHostProperty, BooleanBoxes.Box(value)); } } private static void OnIsItemsHostChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Panel panel = (Panel) d; panel.OnIsItemsHostChanged((bool) e.OldValue, (bool) e.NewValue); } ////// This method is invoked when the IsItemsHost property changes. /// /// The old value of the IsItemsHost property. /// The new value of the IsItemsHost property. protected virtual void OnIsItemsHostChanged(bool oldIsItemsHost, bool newIsItemsHost) { // GetItemsOwner will check IsItemsHost first, so we don't have // to check that IsItemsHost == true before calling it. ItemsControl itemsControl = ItemsControl.GetItemsOwner(this); if (itemsControl != null) { // ItemsHost should be the "root" element which has // IsItemsHost = true on it. In the case of grouping, // IsItemsHost is true on all panels which are generating // content. Thus, we care only about the panel which // is generating content for the ItemsControl. IItemContainerGenerator generator = itemsControl.ItemContainerGenerator as IItemContainerGenerator; if (generator != null && generator == generator.GetItemContainerGeneratorForPanel(this)) { itemsControl.ItemsHost = this; } } VerifyBoundState(); } ////// Orientation of the panel if its layout is in one dimension. /// Otherwise HasLogicalOrientation is false and LogicalOrientation should be ignored /// protected internal virtual Orientation LogicalOrientation { get { return Orientation.Vertical; } } ////// HasLogicalOrientation is true in case the panel layout is only one dimension (Stack panel). /// protected internal virtual bool HasLogicalOrientation { get { return false; } } #endregion #region Protected Methods ////// Returns a UIElementCollection of children - added by user or generated from data binding. /// Panel-derived classes should use this collection for all internal purposes, including /// MeasureOverride/ArrangeOverride overrides. /// protected internal UIElementCollection InternalChildren { get { VerifyBoundState(); if(IsItemsHost && _itemContainerGenerator == null) //new panel, initialize { reGenerateChildren(); } else if(!IsItemsHost && _uiElementCollection == null) //nobody used it yet in Direct Panel { _uiElementCollection = CreateUIElementCollection(this); } return _uiElementCollection; } } ////// Gets the Visual children count. /// protected override int VisualChildrenCount { get { if (_uiElementCollection == null) { return 0; } else { return _uiElementCollection.Count; } } } ////// Gets the Visual child at the specified index. /// protected override Visual GetVisualChild(int index) { if (_uiElementCollection == null) { throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange)); } if (IsZStateDirty) { RecomputeZState(); } int visualIndex = _zLut != null ? _zLut[index] : index; return _uiElementCollection[visualIndex]; } ////// Creates a new UIElementCollection. Panel-derived class can create its own version of /// UIElementCollection -derived class to add cached information to every child or to /// intercept any Add/Remove actions (for example, for incremental layout update) /// protected virtual UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent) { return new UIElementCollection(this, logicalParent); } ////// Flag to indicate that the panel should support virtualization. /// private bool SupportsVirtualization { get { return GetBoolField(BoolField.SupportsVirtualization); } } ////// The generator associated with this panel. /// internal IItemContainerGenerator Generator { get { return _itemContainerGenerator; } } #endregion #region Internal Properties // // Bool field used by VirtualizingStackPanel // internal bool VSP_IsVirtualizing { get { return GetBoolField(BoolField.IsVirtualizing); } set { SetBoolField(BoolField.IsVirtualizing, value); } } // // Bool field used by VirtualizingStackPanel // internal bool VSP_HasMeasured { get { return GetBoolField(BoolField.HasMeasured); } set { SetBoolField(BoolField.HasMeasured, value); } } // // Bool field used by VirtualizingStackPanel // internal bool VSP_IsPixelBased { get { return GetBoolField(BoolField.IsPixelBased); } set { SetBoolField(BoolField.IsPixelBased, value); } } #endregion #region Private Methods private void VerifyBoundState() { bool bound = IsItemsHost; // if the panel becomes "unbound" while attached to a generator, this // method detaches it and makes it really behave like "unbound". This // can happen because of a style change, a theme change, etc. (bugs // 942265, 948170, and dupes). It returns the correct "bound" state, after // the dust has settled. // // This is really a workaround for a more general problem. // if (!bound && _itemContainerGenerator != null) { _itemContainerGenerator.ItemsChanged -= new ItemsChangedEventHandler(OnItemsChanged); ((IItemContainerGenerator)_itemContainerGenerator).RemoveAll(); _itemContainerGenerator = null; if(_uiElementCollection != null && _uiElementCollection.Count > 0) { _uiElementCollection.ClearInternal(); OnClearChildrenInternal(); } } // In case of transition Direct_with_Children -> Bound, remove manually inserted // children and prepare for subsequent generations if(bound && _itemContainerGenerator == null && _uiElementCollection != null && _uiElementCollection.Count != 0) { _uiElementCollection.ClearInternal(); OnClearChildrenInternal(); } } //"actually data-bound and using generator" This is true if Panel is //not only marked as IsItemsHost but actually has requested Generator to //generate items and thus "owns" those items. //In this case, Children collection becomes read-only //Cases when it is not true include "direct" usage - IsItemsHost=false and //useges when panel is data-bound but derived class avoids getting INternalChidlren nor Children //and rather calls CreateUIElementCollection and then drives Generator itself. internal bool IsDataBound { get { return IsItemsHost && _itemContainerGenerator != null; } } ///Used by subclasses to decide whether to call through a profiling stub internal static bool IsAboutToGenerateContent(Panel panel) { return panel.IsItemsHost && panel._itemContainerGenerator == null; } // Removes previously generated children and re-generates the whole collection // This is done first time or when Refresh command is obtained from the collection private void reGenerateChildren() { // first time - listen for events from generator if (_itemContainerGenerator == null) { _itemContainerGenerator = getGenerator().GetItemContainerGeneratorForPanel(this); if (_itemContainerGenerator != null) { _itemContainerGenerator.ItemsChanged += new ItemsChangedEventHandler(OnItemsChanged); ((IItemContainerGenerator)_itemContainerGenerator).RemoveAll(); } // if the generator is null (e.g. for a user-declared GroupItem - bug 108423), // create an empty Children collection. It will never acquire any children. } IItemContainerGenerator generator = (IItemContainerGenerator)_itemContainerGenerator; // If children were already produced, remove them all if(_uiElementCollection != null && _uiElementCollection.Count > 0) { generator.RemoveAll(); _uiElementCollection.ClearInternal(); OnClearChildrenInternal(); } // Create new empty collection, passing ItemsOwner as logical parent for future children // Pass null so generated containers are not assigned any LogicalParent if(_uiElementCollection == null) _uiElementCollection = CreateUIElementCollection(null); if (SupportsVirtualization) { return; } if (generator != null) { using (generator.StartAt(new GeneratorPosition(-1, 0), GeneratorDirection.Forward)) { UIElement elem; while ((elem = generator.GenerateNext() as UIElement) != null) { _uiElementCollection.AddInternal(elem); generator.PrepareItemContainer(elem); } } } } private void OnItemsChanged(object sender, ItemsChangedEventArgs args) { VerifyBoundState(); if (!IsItemsHost) return; // style changed - this panel is no longer in use //sanity check if(_itemContainerGenerator == null) throw new InvalidOperationException(); OnItemsChangedInternal(sender, args); InvalidateMeasure(); } internal virtual void OnItemsChangedInternal(object sender, ItemsChangedEventArgs args) { switch (args.Action) { case NotifyCollectionChangedAction.Add: addChildren(args.Position, args.ItemCount); break; case NotifyCollectionChangedAction.Remove: removeChildren(args.Position, args.ItemUICount); break; case NotifyCollectionChangedAction.Replace: replaceChildren(args.Position, args.ItemCount); break; case NotifyCollectionChangedAction.Move: moveChildren(args.OldPosition, args.Position, args.ItemUICount); break; case NotifyCollectionChangedAction.Reset: reGenerateChildren(); break; } } internal virtual void OnClearChildrenInternal() { } private void addChildren(GeneratorPosition pos, int itemCount) { IItemContainerGenerator generator = getGenerator(); generator = generator.GetItemContainerGeneratorForPanel(this); using (generator.StartAt(pos, GeneratorDirection.Forward)) { for(int i=0; i/// /// protected internal override void OnVisualChildrenChanged( DependencyObject visualAdded, DependencyObject visualRemoved) { if (!IsZStateDirty) { if (IsZStateDiverse) { // if children have different ZIndex values, // then _zLut have to be recomputed IsZStateDirty = true; } else if (visualAdded != null) { // if current children have consonant ZIndex values, // then _zLut have to be recomputed, only if the new // child makes z state diverse int zNew = (int)visualAdded.GetValue(ZIndexProperty); if (zNew != _zConsonant) { IsZStateDirty = true; } } } base.OnVisualChildrenChanged(visualAdded, visualRemoved); } /// /// ZIndex property is an attached property. Panel reads it to alter the order /// of children rendering. Children with greater values will be rendered on top of /// children with lesser values. /// In case of two children with the same ZIndex property value, order of rendering /// is determined by their order in Panel.Children collection. /// public static readonly DependencyProperty ZIndexProperty = DependencyProperty.RegisterAttached( "ZIndex", typeof(int), typeof(Panel), new FrameworkPropertyMetadata( c_zDefaultValue, new PropertyChangedCallback(OnZIndexPropertyChanged))); ////// Helper for setting ZIndex property on a UIElement. /// /// UIElement to set ZIndex property on. /// ZIndex property value. public static void SetZIndex(UIElement element, int value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(ZIndexProperty, value); } ////// Helper for reading ZIndex property from a UIElement. /// /// UIElement to read ZIndex property from. ///ZIndex property value. public static int GetZIndex(UIElement element) { if (element == null) { throw new ArgumentNullException("element"); } return ((int)element.GetValue(ZIndexProperty)); } ////// private static void OnZIndexPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { int oldValue = (int)e.OldValue; int newValue = (int)e.NewValue; if (oldValue == newValue) return; UIElement child = d as UIElement; if (child == null) return; Panel panel = child.InternalVisualParent as Panel; if (panel == null) return; panel.InvalidateZState(); } ////// /// Sets the Z state to be dirty /// internal void InvalidateZState() { if (!IsZStateDirty && _uiElementCollection != null) { InvalidateZOrder(); } IsZStateDirty = true; } private bool IsZStateDirty { get { return GetBoolField(BoolField.IsZStateDirty); } set { SetBoolField(BoolField.IsZStateDirty, value); } } private bool IsZStateDiverse { get { return GetBoolField(BoolField.IsZStateDiverse); } set { SetBoolField(BoolField.IsZStateDiverse, value); } } // Helper method to update this panel's state related to children rendering order handling private void RecomputeZState() { int count = _uiElementCollection.Count; bool isDiverse = false; bool lutRequired = false; int zIndexDefaultValue = (int)ZIndexProperty.GetDefaultValue(DependencyObjectType); int consonant = zIndexDefaultValue; System.Collections.Generic.ListstableKeyValues = null; if (count > 0) { if (_uiElementCollection[0] != null) { consonant = (int)_uiElementCollection[0].GetValue(ZIndexProperty); } if (count > 1) { stableKeyValues = new System.Collections.Generic.List (count); stableKeyValues.Add((Int64)consonant << 32); int prevZ = consonant; int i = 1; do { int z = _uiElementCollection[i] != null ? (int)_uiElementCollection[i].GetValue(ZIndexProperty) : zIndexDefaultValue; // this way of calculating values of stableKeyValues required to // 1) workaround the fact that Array.Sort is not stable (does not preserve the original // order of elements if the keys are equal) // 2) avoid O(N^2) performance of Array.Sort, which is QuickSort, which is known to become O(N^2) // on sorting N eqial keys stableKeyValues.Add(((Int64)z << 32) + i); // look-up-table is required iff z's are not monotonically increasing function of index. // in other words if stableKeyValues[i] >= stableKeyValues[i-1] then calculated look-up-table // is guaranteed to be degenerated... lutRequired |= z < prevZ; prevZ = z; isDiverse |= (z != consonant); } while (++i < count); } } if (lutRequired) { stableKeyValues.Sort(); if (_zLut == null || _zLut.Length != count) { _zLut = new int[count]; } for (int i = 0; i < count; ++i) { _zLut[i] = (int)(stableKeyValues[i] & 0xffffffff); } } else { _zLut = null; } IsZStateDiverse = isDiverse; _zConsonant = consonant; IsZStateDirty = false; } #endregion ZIndex Support } } // 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. // // File: Panel.cs // // Description: Contains the Panel base class. // Spec at http://avalon/layout/Specs/Panel.xml // // History: // 06/30/2003 : greglett - Added to WCP branch (was Stack.cs in old branch) // //--------------------------------------------------------------------------- using MS.Internal; using MS.Internal.Controls; using MS.Internal.KnownBoxes; using MS.Internal.PresentationFramework; using MS.Utility; using System.Collections; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Windows.Threading; using System.Windows.Media; using System.Windows.Markup; // IAddChild, ContentPropertyAttribute using System.Windows.Documents; using System.Windows.Controls.Primitives; // IItemContainerGenerator using System; namespace System.Windows.Controls { /// /// [Localizability(LocalizationCategory.Ignore)] [ContentProperty("Children")] public abstract class Panel : FrameworkElement, IAddChild { //------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors ////// Default DependencyObject constructor /// ////// Automatic determination of current Dispatcher. Use alternative constructor /// that accepts a Dispatcher for best performance. /// protected Panel() : base() { _zConsonant = (int)ZIndexProperty.GetDefaultValue(DependencyObjectType); } ////// Initializes a new instance of a Panel. /// /// Whether the panel should support virtualization. internal Panel(bool supportsVirtualization) : base() { SetBoolField(BoolField.SupportsVirtualization, supportsVirtualization); _zConsonant = (int)ZIndexProperty.GetDefaultValue(DependencyObjectType); } ////// Static Ctor to create default style sheet. /// static Panel() { } #endregion //-------------------------------------------------------------------- // // Public Methods // //------------------------------------------------------------------- #region Public Methods ////// Override from UIElement /// protected override void OnRender(DrawingContext dc) { // Draw background in rectangle inside border. Brush background = this.Background; if (background != null) { dc.DrawRectangle(background, null, new Rect(0, 0, RenderSize.Width, RenderSize.Height)); } } ////// This method is called to Add the object as a child of the Panel. This method is used primarily /// by the parser. /// /// /// The object to add as a child; it must be a UIElement. /// ///void IAddChild.AddChild (Object value) { if (value == null) { throw new ArgumentNullException("value"); } if(IsItemsHost) { throw new InvalidOperationException(SR.Get(SRID.Panel_BoundPanel_NoChildren)); } UIElement uie = value as UIElement; if (uie == null) { throw new ArgumentException(SR.Get(SRID.UnexpectedParameterType, value.GetType(), typeof(UIElement)), "value"); } Children.Add(uie); } /// /// This method is called by the parser when text appears under the tag in markup. /// As default Panels do not support text, calling this method has no effect. /// /// /// Text to add as a child. /// void IAddChild.AddText (string text) { XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this); } #endregion //-------------------------------------------------------------------- // // Public Properties + Avalon Dependency ID's // //-------------------------------------------------------------------- #region Public Properties ////// The Background property defines the brush used to fill the area between borders. /// public Brush Background { get { return (Brush) GetValue(BackgroundProperty); } set { SetValue(BackgroundProperty, value); } } ////// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register("Background", typeof(Brush), typeof(Panel), new FrameworkPropertyMetadata((Brush)null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender)); ///property. /// /// Returns enumerator to logical children. /// protected internal override IEnumerator LogicalChildren { get { if ((this.VisualChildrenCount == 0) || IsItemsHost) { // empty panel or a panel being used as the items // host has *no* logical children; give empty enumerator return EmptyEnumerator.Instance; } // otherwise, its logical children is its visual children return this.Children.GetEnumerator(); } } ////// Returns a UIElementCollection of children for user to add/remove children manually /// Returns read-only collection if Panel is data-bound (no manual control of children is possible, /// the associated ItemsControl completely overrides children) /// Note: the derived Panel classes should never use this collection for /// internal purposes like in their MeasureOverride or ArrangeOverride. /// They should use InternalChildren instead, because InternalChildren /// is always present and either is a mirror of public Children collection (in case of Direct Panel) /// or is generated from data binding. /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public UIElementCollection Children { get { // May want to throw an InvalidOperationException if SupportsVirtualization is true //When we will change from UIElementCollection to IList, we might //consider returning a wrapper IList here which coudl be read-only for mutating methods //while INternalChildren could be R/W even in case of Generator attached. return InternalChildren; } } /// /// This method is used by TypeDescriptor to determine if this property should /// be serialized. /// // Should serialize property Children only if it is non empty [EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeChildren() { if (!IsItemsHost) { if (Children != null && Children.Count > 0) { return true; } } return false; } ////// The DependencyProperty for the IsItemsHost property. /// Flags: NotDataBindable /// Default Value: false /// public static readonly DependencyProperty IsItemsHostProperty = DependencyProperty.Register( "IsItemsHost", typeof(bool), typeof(Panel), new FrameworkPropertyMetadata( BooleanBoxes.FalseBox, // defaultValue FrameworkPropertyMetadataOptions.NotDataBindable, new PropertyChangedCallback(OnIsItemsHostChanged))); ////// IsItemsHost is set to true to indicate that the panel /// is the container for UI generated for the items of an /// ItemsControl. It is typically set in a style for an ItemsControl. /// [Bindable(false), Category("Behavior")] public bool IsItemsHost { get { return (bool) GetValue(IsItemsHostProperty); } set { SetValue(IsItemsHostProperty, BooleanBoxes.Box(value)); } } private static void OnIsItemsHostChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Panel panel = (Panel) d; panel.OnIsItemsHostChanged((bool) e.OldValue, (bool) e.NewValue); } ////// This method is invoked when the IsItemsHost property changes. /// /// The old value of the IsItemsHost property. /// The new value of the IsItemsHost property. protected virtual void OnIsItemsHostChanged(bool oldIsItemsHost, bool newIsItemsHost) { // GetItemsOwner will check IsItemsHost first, so we don't have // to check that IsItemsHost == true before calling it. ItemsControl itemsControl = ItemsControl.GetItemsOwner(this); if (itemsControl != null) { // ItemsHost should be the "root" element which has // IsItemsHost = true on it. In the case of grouping, // IsItemsHost is true on all panels which are generating // content. Thus, we care only about the panel which // is generating content for the ItemsControl. IItemContainerGenerator generator = itemsControl.ItemContainerGenerator as IItemContainerGenerator; if (generator != null && generator == generator.GetItemContainerGeneratorForPanel(this)) { itemsControl.ItemsHost = this; } } VerifyBoundState(); } ////// Orientation of the panel if its layout is in one dimension. /// Otherwise HasLogicalOrientation is false and LogicalOrientation should be ignored /// protected internal virtual Orientation LogicalOrientation { get { return Orientation.Vertical; } } ////// HasLogicalOrientation is true in case the panel layout is only one dimension (Stack panel). /// protected internal virtual bool HasLogicalOrientation { get { return false; } } #endregion #region Protected Methods ////// Returns a UIElementCollection of children - added by user or generated from data binding. /// Panel-derived classes should use this collection for all internal purposes, including /// MeasureOverride/ArrangeOverride overrides. /// protected internal UIElementCollection InternalChildren { get { VerifyBoundState(); if(IsItemsHost && _itemContainerGenerator == null) //new panel, initialize { reGenerateChildren(); } else if(!IsItemsHost && _uiElementCollection == null) //nobody used it yet in Direct Panel { _uiElementCollection = CreateUIElementCollection(this); } return _uiElementCollection; } } ////// Gets the Visual children count. /// protected override int VisualChildrenCount { get { if (_uiElementCollection == null) { return 0; } else { return _uiElementCollection.Count; } } } ////// Gets the Visual child at the specified index. /// protected override Visual GetVisualChild(int index) { if (_uiElementCollection == null) { throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange)); } if (IsZStateDirty) { RecomputeZState(); } int visualIndex = _zLut != null ? _zLut[index] : index; return _uiElementCollection[visualIndex]; } ////// Creates a new UIElementCollection. Panel-derived class can create its own version of /// UIElementCollection -derived class to add cached information to every child or to /// intercept any Add/Remove actions (for example, for incremental layout update) /// protected virtual UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent) { return new UIElementCollection(this, logicalParent); } ////// Flag to indicate that the panel should support virtualization. /// private bool SupportsVirtualization { get { return GetBoolField(BoolField.SupportsVirtualization); } } ////// The generator associated with this panel. /// internal IItemContainerGenerator Generator { get { return _itemContainerGenerator; } } #endregion #region Internal Properties // // Bool field used by VirtualizingStackPanel // internal bool VSP_IsVirtualizing { get { return GetBoolField(BoolField.IsVirtualizing); } set { SetBoolField(BoolField.IsVirtualizing, value); } } // // Bool field used by VirtualizingStackPanel // internal bool VSP_HasMeasured { get { return GetBoolField(BoolField.HasMeasured); } set { SetBoolField(BoolField.HasMeasured, value); } } // // Bool field used by VirtualizingStackPanel // internal bool VSP_IsPixelBased { get { return GetBoolField(BoolField.IsPixelBased); } set { SetBoolField(BoolField.IsPixelBased, value); } } #endregion #region Private Methods private void VerifyBoundState() { bool bound = IsItemsHost; // if the panel becomes "unbound" while attached to a generator, this // method detaches it and makes it really behave like "unbound". This // can happen because of a style change, a theme change, etc. (bugs // 942265, 948170, and dupes). It returns the correct "bound" state, after // the dust has settled. // // This is really a workaround for a more general problem. // if (!bound && _itemContainerGenerator != null) { _itemContainerGenerator.ItemsChanged -= new ItemsChangedEventHandler(OnItemsChanged); ((IItemContainerGenerator)_itemContainerGenerator).RemoveAll(); _itemContainerGenerator = null; if(_uiElementCollection != null && _uiElementCollection.Count > 0) { _uiElementCollection.ClearInternal(); OnClearChildrenInternal(); } } // In case of transition Direct_with_Children -> Bound, remove manually inserted // children and prepare for subsequent generations if(bound && _itemContainerGenerator == null && _uiElementCollection != null && _uiElementCollection.Count != 0) { _uiElementCollection.ClearInternal(); OnClearChildrenInternal(); } } //"actually data-bound and using generator" This is true if Panel is //not only marked as IsItemsHost but actually has requested Generator to //generate items and thus "owns" those items. //In this case, Children collection becomes read-only //Cases when it is not true include "direct" usage - IsItemsHost=false and //useges when panel is data-bound but derived class avoids getting INternalChidlren nor Children //and rather calls CreateUIElementCollection and then drives Generator itself. internal bool IsDataBound { get { return IsItemsHost && _itemContainerGenerator != null; } } ///Used by subclasses to decide whether to call through a profiling stub internal static bool IsAboutToGenerateContent(Panel panel) { return panel.IsItemsHost && panel._itemContainerGenerator == null; } // Removes previously generated children and re-generates the whole collection // This is done first time or when Refresh command is obtained from the collection private void reGenerateChildren() { // first time - listen for events from generator if (_itemContainerGenerator == null) { _itemContainerGenerator = getGenerator().GetItemContainerGeneratorForPanel(this); if (_itemContainerGenerator != null) { _itemContainerGenerator.ItemsChanged += new ItemsChangedEventHandler(OnItemsChanged); ((IItemContainerGenerator)_itemContainerGenerator).RemoveAll(); } // if the generator is null (e.g. for a user-declared GroupItem - bug 108423), // create an empty Children collection. It will never acquire any children. } IItemContainerGenerator generator = (IItemContainerGenerator)_itemContainerGenerator; // If children were already produced, remove them all if(_uiElementCollection != null && _uiElementCollection.Count > 0) { generator.RemoveAll(); _uiElementCollection.ClearInternal(); OnClearChildrenInternal(); } // Create new empty collection, passing ItemsOwner as logical parent for future children // Pass null so generated containers are not assigned any LogicalParent if(_uiElementCollection == null) _uiElementCollection = CreateUIElementCollection(null); if (SupportsVirtualization) { return; } if (generator != null) { using (generator.StartAt(new GeneratorPosition(-1, 0), GeneratorDirection.Forward)) { UIElement elem; while ((elem = generator.GenerateNext() as UIElement) != null) { _uiElementCollection.AddInternal(elem); generator.PrepareItemContainer(elem); } } } } private void OnItemsChanged(object sender, ItemsChangedEventArgs args) { VerifyBoundState(); if (!IsItemsHost) return; // style changed - this panel is no longer in use //sanity check if(_itemContainerGenerator == null) throw new InvalidOperationException(); OnItemsChangedInternal(sender, args); InvalidateMeasure(); } internal virtual void OnItemsChangedInternal(object sender, ItemsChangedEventArgs args) { switch (args.Action) { case NotifyCollectionChangedAction.Add: addChildren(args.Position, args.ItemCount); break; case NotifyCollectionChangedAction.Remove: removeChildren(args.Position, args.ItemUICount); break; case NotifyCollectionChangedAction.Replace: replaceChildren(args.Position, args.ItemCount); break; case NotifyCollectionChangedAction.Move: moveChildren(args.OldPosition, args.Position, args.ItemUICount); break; case NotifyCollectionChangedAction.Reset: reGenerateChildren(); break; } } internal virtual void OnClearChildrenInternal() { } private void addChildren(GeneratorPosition pos, int itemCount) { IItemContainerGenerator generator = getGenerator(); generator = generator.GetItemContainerGeneratorForPanel(this); using (generator.StartAt(pos, GeneratorDirection.Forward)) { for(int i=0; i/// /// protected internal override void OnVisualChildrenChanged( DependencyObject visualAdded, DependencyObject visualRemoved) { if (!IsZStateDirty) { if (IsZStateDiverse) { // if children have different ZIndex values, // then _zLut have to be recomputed IsZStateDirty = true; } else if (visualAdded != null) { // if current children have consonant ZIndex values, // then _zLut have to be recomputed, only if the new // child makes z state diverse int zNew = (int)visualAdded.GetValue(ZIndexProperty); if (zNew != _zConsonant) { IsZStateDirty = true; } } } base.OnVisualChildrenChanged(visualAdded, visualRemoved); } /// /// ZIndex property is an attached property. Panel reads it to alter the order /// of children rendering. Children with greater values will be rendered on top of /// children with lesser values. /// In case of two children with the same ZIndex property value, order of rendering /// is determined by their order in Panel.Children collection. /// public static readonly DependencyProperty ZIndexProperty = DependencyProperty.RegisterAttached( "ZIndex", typeof(int), typeof(Panel), new FrameworkPropertyMetadata( c_zDefaultValue, new PropertyChangedCallback(OnZIndexPropertyChanged))); ////// Helper for setting ZIndex property on a UIElement. /// /// UIElement to set ZIndex property on. /// ZIndex property value. public static void SetZIndex(UIElement element, int value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(ZIndexProperty, value); } ////// Helper for reading ZIndex property from a UIElement. /// /// UIElement to read ZIndex property from. ///ZIndex property value. public static int GetZIndex(UIElement element) { if (element == null) { throw new ArgumentNullException("element"); } return ((int)element.GetValue(ZIndexProperty)); } ////// private static void OnZIndexPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { int oldValue = (int)e.OldValue; int newValue = (int)e.NewValue; if (oldValue == newValue) return; UIElement child = d as UIElement; if (child == null) return; Panel panel = child.InternalVisualParent as Panel; if (panel == null) return; panel.InvalidateZState(); } ////// /// Sets the Z state to be dirty /// internal void InvalidateZState() { if (!IsZStateDirty && _uiElementCollection != null) { InvalidateZOrder(); } IsZStateDirty = true; } private bool IsZStateDirty { get { return GetBoolField(BoolField.IsZStateDirty); } set { SetBoolField(BoolField.IsZStateDirty, value); } } private bool IsZStateDiverse { get { return GetBoolField(BoolField.IsZStateDiverse); } set { SetBoolField(BoolField.IsZStateDiverse, value); } } // Helper method to update this panel's state related to children rendering order handling private void RecomputeZState() { int count = _uiElementCollection.Count; bool isDiverse = false; bool lutRequired = false; int zIndexDefaultValue = (int)ZIndexProperty.GetDefaultValue(DependencyObjectType); int consonant = zIndexDefaultValue; System.Collections.Generic.ListstableKeyValues = null; if (count > 0) { if (_uiElementCollection[0] != null) { consonant = (int)_uiElementCollection[0].GetValue(ZIndexProperty); } if (count > 1) { stableKeyValues = new System.Collections.Generic.List (count); stableKeyValues.Add((Int64)consonant << 32); int prevZ = consonant; int i = 1; do { int z = _uiElementCollection[i] != null ? (int)_uiElementCollection[i].GetValue(ZIndexProperty) : zIndexDefaultValue; // this way of calculating values of stableKeyValues required to // 1) workaround the fact that Array.Sort is not stable (does not preserve the original // order of elements if the keys are equal) // 2) avoid O(N^2) performance of Array.Sort, which is QuickSort, which is known to become O(N^2) // on sorting N eqial keys stableKeyValues.Add(((Int64)z << 32) + i); // look-up-table is required iff z's are not monotonically increasing function of index. // in other words if stableKeyValues[i] >= stableKeyValues[i-1] then calculated look-up-table // is guaranteed to be degenerated... lutRequired |= z < prevZ; prevZ = z; isDiverse |= (z != consonant); } while (++i < count); } } if (lutRequired) { stableKeyValues.Sort(); if (_zLut == null || _zLut.Length != count) { _zLut = new int[count]; } for (int i = 0; i < count; ++i) { _zLut[i] = (int)(stableKeyValues[i] & 0xffffffff); } } else { _zLut = null; } IsZStateDiverse = isDiverse; _zConsonant = consonant; IsZStateDirty = false; } #endregion ZIndex Support } } // 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
- MaskedTextBoxTextEditor.cs
- XPathCompileException.cs
- ECDiffieHellmanCngPublicKey.cs
- InvokeWebServiceDesigner.cs
- GridViewRowEventArgs.cs
- ValidatedControlConverter.cs
- FrameworkElementAutomationPeer.cs
- SpellerHighlightLayer.cs
- SqlDependency.cs
- WebWorkflowRole.cs
- FontFamily.cs
- SqlTransaction.cs
- Graphics.cs
- PowerEase.cs
- TypeConverterHelper.cs
- IsolationInterop.cs
- TextTreeUndo.cs
- InvokeSchedule.cs
- UnsafeNativeMethods.cs
- TdsParserStaticMethods.cs
- MissingMemberException.cs
- PropertyTabChangedEvent.cs
- IntranetCredentialPolicy.cs
- TraceData.cs
- TransactionScopeDesigner.cs
- Queue.cs
- SystemFonts.cs
- FileController.cs
- COM2ComponentEditor.cs
- TypeReference.cs
- UnicodeEncoding.cs
- RegistryPermission.cs
- WebPartExportVerb.cs
- ValidationUtility.cs
- AttributeCollection.cs
- ListChangedEventArgs.cs
- DesignerUtils.cs
- HashCryptoHandle.cs
- InstanceOwnerQueryResult.cs
- CleanUpVirtualizedItemEventArgs.cs
- SoapServerMessage.cs
- BitmapImage.cs
- NavigationEventArgs.cs
- Int32AnimationBase.cs
- PropertyMapper.cs
- OleAutBinder.cs
- TokenBasedSet.cs
- WebServiceErrorEvent.cs
- SecureStringHasher.cs
- Pool.cs
- CapabilitiesState.cs
- PropertyFilterAttribute.cs
- FieldDescriptor.cs
- SendMailErrorEventArgs.cs
- EventWaitHandleSecurity.cs
- ItemCollection.cs
- dataobject.cs
- ValueProviderWrapper.cs
- PersonalizableTypeEntry.cs
- SizeFConverter.cs
- ProfileService.cs
- Cursors.cs
- DataErrorValidationRule.cs
- IgnoreFlushAndCloseStream.cs
- TypeSystemProvider.cs
- nulltextcontainer.cs
- IdnElement.cs
- EpmSyndicationContentSerializer.cs
- XmlWrappingReader.cs
- ActionFrame.cs
- httpapplicationstate.cs
- DefaultValueAttribute.cs
- ResizeGrip.cs
- Error.cs
- VideoDrawing.cs
- EventDescriptor.cs
- ComponentEvent.cs
- RecordBuilder.cs
- XmlConvert.cs
- BitmapEffectDrawingContextWalker.cs
- StringResourceManager.cs
- recordstatescratchpad.cs
- Size.cs
- MouseEventArgs.cs
- AutomationProperties.cs
- QueryContinueDragEventArgs.cs
- CellParaClient.cs
- SimpleFieldTemplateFactory.cs
- ObjectAnimationBase.cs
- SqlVersion.cs
- PolicyLevel.cs
- Point.cs
- KnownTypeAttribute.cs
- CompiledQueryCacheKey.cs
- SqlError.cs
- XmlWriter.cs
- HttpWebRequest.cs
- DataGridState.cs
- CheckBoxAutomationPeer.cs
- PopupControlService.cs