panel.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Controls / panel.cs / 1 / panel.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// File: Panel.cs 
//
// Description: Contains the Panel base class. 
//              Spec at [....]/layout/Specs/Panel.xml 
//
// History: 
//  06/30/2003 : [....]  - 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 virtualizing) : base()
        { 
            SetBoolField(BoolField.IsVirtualizing, virtualizing);
            _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  property.
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty BackgroundProperty =
                DependencyProperty.Register("Background", 
                        typeof(Brush), 
                        typeof(Panel),
                        new FrameworkPropertyMetadata((Brush)null, 
                                FrameworkPropertyMetadataOptions.AffectsRender |
                                FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender));

        ///  
        /// 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 IsVirtualizing 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.
        /// 
        internal bool IsVirtualizing
        { 
            get
            { 
                return GetBoolField(BoolField.IsVirtualizing); 
            }
        } 

        /// 
        ///     The generator associated with this panel.
        ///  
        internal IItemContainerGenerator Generator
        { 
            get 
            {
                return _itemContainerGenerator; 
            }
        }

        #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);
                _itemContainerGenerator.ItemsChanged += new ItemsChangedEventHandler(OnItemsChanged); 
                ((IItemContainerGenerator)_itemContainerGenerator).RemoveAll();
            } 
 
            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 (IsVirtualizing) 
            { 
                return;
            } 

            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 cirrent 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;

            if (    !panel.IsZStateDirty 
                &&  panel._uiElementCollection != null    )
            { 
                panel.InvalidateZOrder(); 
            }
 
            panel.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.List stableKeyValues = 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

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK