Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / 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 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 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 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.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.
//----------------------------------------------------------------------------
//
// 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 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 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.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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WindowsFormsHelpers.cs
- FunctionParameter.cs
- SingleObjectCollection.cs
- FormsAuthenticationCredentials.cs
- TemplateXamlTreeBuilder.cs
- XhtmlBasicPhoneCallAdapter.cs
- ObjectContextServiceProvider.cs
- ContentPlaceHolder.cs
- BrowserCapabilitiesFactory.cs
- WebEventCodes.cs
- RemoteX509AsymmetricSecurityKey.cs
- ColumnProvider.cs
- COM2ComponentEditor.cs
- SpecularMaterial.cs
- MouseButtonEventArgs.cs
- _SecureChannel.cs
- RelatedPropertyManager.cs
- WindowsIPAddress.cs
- ResourceDisplayNameAttribute.cs
- MemberRelationshipService.cs
- thaishape.cs
- ProfileServiceManager.cs
- MethodCallTranslator.cs
- UniqueEventHelper.cs
- TextFindEngine.cs
- CheckBox.cs
- FormCollection.cs
- Transform3DGroup.cs
- DragDrop.cs
- TagPrefixInfo.cs
- CmsUtils.cs
- BitmapSource.cs
- SizeF.cs
- Decimal.cs
- PointAnimationClockResource.cs
- UnhandledExceptionEventArgs.cs
- TypeDescriptor.cs
- FormViewDeletedEventArgs.cs
- DoubleConverter.cs
- BitmapData.cs
- PasswordBoxAutomationPeer.cs
- FixedNode.cs
- HttpFileCollectionWrapper.cs
- PathParser.cs
- XPathNodeHelper.cs
- SafeWaitHandle.cs
- HostExecutionContextManager.cs
- ContextQuery.cs
- TemplateControlCodeDomTreeGenerator.cs
- SystemWebCachingSectionGroup.cs
- XmlProcessingInstruction.cs
- WebRequestModuleElement.cs
- UrlAuthorizationModule.cs
- WebSysDefaultValueAttribute.cs
- WebPart.cs
- ParentUndoUnit.cs
- RuleRef.cs
- MetafileHeaderEmf.cs
- Perspective.cs
- ParameterCollection.cs
- CurrencyWrapper.cs
- PrintDialog.cs
- XamlToRtfWriter.cs
- ObjectDataSourceMethodEventArgs.cs
- OleDbErrorCollection.cs
- DispatcherObject.cs
- CodeEventReferenceExpression.cs
- AddIn.cs
- XmlSchemaType.cs
- InputElement.cs
- NamedPipeChannelFactory.cs
- ReaderWriterLock.cs
- DataGridViewBindingCompleteEventArgs.cs
- OracleRowUpdatingEventArgs.cs
- GridViewCommandEventArgs.cs
- Deserializer.cs
- ServerIdentity.cs
- WebPartAuthorizationEventArgs.cs
- ListViewGroupItemCollection.cs
- ReachVisualSerializerAsync.cs
- WebBrowserUriTypeConverter.cs
- ArraySet.cs
- EventProxy.cs
- Viewport2DVisual3D.cs
- ToolStripPanelRow.cs
- EncryptedReference.cs
- BitVec.cs
- ObjectFactoryCodeDomTreeGenerator.cs
- ProcessRequestAsyncResult.cs
- ToolStripSeparator.cs
- DetailsViewUpdatedEventArgs.cs
- GeneratedCodeAttribute.cs
- DynamicRenderer.cs
- StrongTypingException.cs
- ProtocolProfile.cs
- VisualStyleElement.cs
- PersonalizableTypeEntry.cs
- RoutedUICommand.cs
- Latin1Encoding.cs
- ProcessThread.cs