|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections;
using System.ComponentModel;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Diagnostics;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Markup;
#if DEBUG
#endif
using MS.Internal;
using MS.Internal.KnownBoxes;
using MS.Internal.PresentationFramework;
using MS.Utility;
// Disabling 1634 and 1691:
// In order to avoid generating warnings about unknown message numbers and
// unknown pragmas when compiling C# source code with the C# compiler,
// you need to disable warnings 1634 and 1691. (Presharp Documentation)
#pragma warning disable 1634, 1691
namespace System.Windows
{
/// <summary>
/// FrameworkContentElement is used to define
/// structure of generic content.
/// </summary>
/// <remarks>
/// FrameworkContentElement doesnt have its own
/// rendering (rendering must be provided by content
/// owner). <para/>
///
/// FrameworkContentElement <para/>
///
/// <list type="bullet">
/// <item>Directly extends ContentElement </item>
/// <item>Is not a Visual (doesnt provide its own rendering)</item>
/// </list>
/// </remarks>
[StyleTypedProperty(Property = "FocusVisualStyle", StyleTargetType = typeof(Control))]
[XmlLangProperty("Language")]
[UsableDuringInitialization(true)]
public partial class FrameworkContentElement : ContentElement, IFrameworkInputElement, ISupportInitialize, IQueryAmbient
{
/// <summary>
/// Create an instance of a FrameworkContentElement
/// </summary>
/// <remarks>
/// This does basic initialization of the FrameworkContentElement. All subclasses
/// must call the base constructor to perform this initialization
/// </remarks>
public FrameworkContentElement()
{
// Initialize the _styleCache to the default value for StyleProperty.
// If the default value is non-null then wire it to the current instance.
PropertyMetadata metadata = StyleProperty.GetMetadata(DependencyObjectType);
Style defaultValue = (Style)metadata.DefaultValue;
if (defaultValue != null)
{
OnStyleChanged(this, new DependencyPropertyChangedEventArgs(StyleProperty, metadata, null, defaultValue));
}
// Set the ShouldLookupImplicitStyles flag to true if App.Resources has implicit styles.
Application app = Application.Current;
if (app != null && app.HasImplicitStylesInResources)
{
ShouldLookupImplicitStyles = true;
}
}
static FrameworkContentElement()
{
PropertyChangedCallback numberSubstitutionChanged = new PropertyChangedCallback(NumberSubstitutionChanged);
NumberSubstitution.CultureSourceProperty.OverrideMetadata(typeof(FrameworkContentElement), new FrameworkPropertyMetadata(NumberCultureSource.Text, FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, numberSubstitutionChanged));
NumberSubstitution.CultureOverrideProperty.OverrideMetadata(typeof(FrameworkContentElement), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, numberSubstitutionChanged));
NumberSubstitution.SubstitutionProperty.OverrideMetadata(typeof(FrameworkContentElement), new FrameworkPropertyMetadata(NumberSubstitutionMethod.AsCulture, FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, numberSubstitutionChanged));
EventManager.RegisterClassHandler(typeof(FrameworkContentElement), Mouse.QueryCursorEvent, new QueryCursorEventHandler(FrameworkContentElement.OnQueryCursor), true);
AllowDropProperty.OverrideMetadata(typeof(FrameworkContentElement), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits));
Stylus.IsPressAndHoldEnabledProperty.AddOwner(typeof(FrameworkContentElement), new FrameworkPropertyMetadata(BooleanBoxes.TrueBox, FrameworkPropertyMetadataOptions.Inherits));
Stylus.IsFlicksEnabledProperty.AddOwner(typeof(FrameworkContentElement), new FrameworkPropertyMetadata(BooleanBoxes.TrueBox, FrameworkPropertyMetadataOptions.Inherits));
Stylus.IsTapFeedbackEnabledProperty.AddOwner(typeof(FrameworkContentElement), new FrameworkPropertyMetadata(BooleanBoxes.TrueBox, FrameworkPropertyMetadataOptions.Inherits));
Stylus.IsTouchFeedbackEnabledProperty.AddOwner(typeof(FrameworkContentElement), new FrameworkPropertyMetadata(BooleanBoxes.TrueBox, FrameworkPropertyMetadataOptions.Inherits));
// Exposing these events in protected virtual methods
EventManager.RegisterClassHandler(typeof(FrameworkContentElement), ToolTipOpeningEvent, new ToolTipEventHandler(OnToolTipOpeningThunk));
EventManager.RegisterClassHandler(typeof(FrameworkContentElement), ToolTipClosingEvent, new ToolTipEventHandler(OnToolTipClosingThunk));
EventManager.RegisterClassHandler(typeof(FrameworkContentElement), ContextMenuOpeningEvent, new ContextMenuEventHandler(OnContextMenuOpeningThunk));
EventManager.RegisterClassHandler(typeof(FrameworkContentElement), ContextMenuClosingEvent, new ContextMenuEventHandler(OnContextMenuClosingThunk));
EventManager.RegisterClassHandler(typeof(FrameworkContentElement), Keyboard.GotKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(OnGotKeyboardFocus));
EventManager.RegisterClassHandler(typeof(FrameworkContentElement), Keyboard.LostKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(OnLostKeyboardFocus));
}
internal static readonly NumberSubstitution DefaultNumberSubstitution = new NumberSubstitution(
NumberCultureSource.Text, // number substitution in documents defaults to text culture
null, // culture override
NumberSubstitutionMethod.AsCulture
);
private static void NumberSubstitutionChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((FrameworkContentElement) o).HasNumberSubstitutionChanged = true;
}
/// <summary>Style Dependency Property</summary>
[CommonDependencyProperty]
public static readonly DependencyProperty StyleProperty =
FrameworkElement.StyleProperty.AddOwner(
typeof(FrameworkContentElement),
new FrameworkPropertyMetadata(
(Style) null, // default value
FrameworkPropertyMetadataOptions.AffectsMeasure,
new PropertyChangedCallback(OnStyleChanged)));
/// <summary>
/// Style property
/// </summary>
public Style Style
{
get { return _styleCache; }
set { SetValue(StyleProperty, value); }
}
/// <summary>
/// This method is used by TypeDescriptor to determine if this property should
/// be serialized.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool ShouldSerializeStyle()
{
return !IsStyleSetFromGenerator
&& ReadLocalValue(StyleProperty) != DependencyProperty.UnsetValue;
}
// Invoked when the Style property is changed
private static void OnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkContentElement fce = (FrameworkContentElement) d;
fce.HasLocalStyle = (e.NewEntry.BaseValueSourceInternal == BaseValueSourceInternal.Local);
StyleHelper.UpdateStyleCache(null, fce, (Style) e.OldValue, (Style) e.NewValue, ref fce._styleCache);
}
///
protected internal virtual void OnStyleChanged(Style oldStyle, Style newStyle)
{
HasStyleChanged = true;
}
/// <summary>
/// OverridesDefaultStyleProperty
/// </summary>
public static readonly DependencyProperty OverridesDefaultStyleProperty
= FrameworkElement.OverridesDefaultStyleProperty.AddOwner(typeof(FrameworkContentElement),
new FrameworkPropertyMetadata(
BooleanBoxes.FalseBox, // default value
FrameworkPropertyMetadataOptions.AffectsMeasure,
new PropertyChangedCallback(OnThemeStyleKeyChanged)));
/// <summary>
/// This specifies that the current style ignores all
/// properties from the Theme Style
/// </summary>
public bool OverridesDefaultStyle
{
get { return (bool)GetValue(OverridesDefaultStyleProperty); }
set { SetValue(OverridesDefaultStyleProperty, BooleanBoxes.Box(value)); }
}
/// <summary>DefaultStyleKey Dependency Property</summary>
protected internal static readonly DependencyProperty DefaultStyleKeyProperty =
FrameworkElement.DefaultStyleKeyProperty.AddOwner(
typeof(FrameworkContentElement),
new FrameworkPropertyMetadata(
null, // default value
FrameworkPropertyMetadataOptions.AffectsMeasure,
new PropertyChangedCallback(OnThemeStyleKeyChanged)));
/// <summary>
/// DefaultStyleKey property
/// </summary>
protected internal object DefaultStyleKey
{
get { return GetValue(DefaultStyleKeyProperty); }
set { SetValue(DefaultStyleKeyProperty, value); }
}
// This function is called when ThemeStyleKey or OverridesThemeStyle properties change
private static void OnThemeStyleKeyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Re-evaluate ThemeStyle because it is
// a factor of the ThemeStyleKey property
((FrameworkContentElement)d).UpdateThemeStyleProperty();
}
// Cache the ThemeStyle for the current instance if there is a DefaultStyleKey specified for it
internal Style ThemeStyle
{
get { return _themeStyleCache; }
}
// Returns the DependencyObjectType for the registered DefaultStyleKey's default
// value. Controls will override this method to return approriate types.
internal virtual DependencyObjectType DTypeThemeStyleKey
{
get { return null; }
}
// Invoked when the ThemeStyle/DefaultStyleKey property is changed
internal static void OnThemeStyleChanged(DependencyObject d, object oldValue, object newValue)
{
FrameworkContentElement fce = (FrameworkContentElement) d;
StyleHelper.UpdateThemeStyleCache(null, fce, (Style) oldValue, (Style) newValue, ref fce._themeStyleCache);
}
/// <summary>
/// Reference to the style parent of this node, if any.
/// </summary>
/// <returns>
/// Reference to FrameworkElement or FrameworkContentElement whose
/// Template.VisualTree caused this FrameworkContentElement to be created.
/// </returns>
public DependencyObject TemplatedParent
{
get
{
return _templatedParent;
}
}
/// <summary>
/// Check if resource is not empty.
/// Call HasResources before accessing resources every time you need
/// to query for a resource.
/// </summary>
internal bool HasResources
{
get
{
ResourceDictionary resources = ResourcesField.GetValue(this);
return (resources != null &&
((resources.Count > 0) || (resources.MergedDictionaries.Count > 0)));
}
}
/// <summary>
/// Current locally defined Resources
/// </summary>
[Ambient]
public ResourceDictionary Resources
{
get
{
ResourceDictionary resources = ResourcesField.GetValue(this);
if (resources == null)
{
resources = new ResourceDictionary();
resources.AddOwner(this);
ResourcesField.SetValue(this, resources);
}
return resources;
}
set
{
ResourceDictionary oldValue = ResourcesField.GetValue(this);
ResourcesField.SetValue(this, value);
if (oldValue != null)
{
// This element is no longer an owner for the old RD
oldValue.RemoveOwner(this);
}
if (value != null)
{
if (!value.ContainsOwner(this))
{
// This element is an owner for the new RD
value.AddOwner(this);
}
}
// Invalidate ResourceReference properties for this subtree
// Invalidating only when not empty will not take care of the case where
// a RD is not sealed, and its entire contents are cleared. This needs to be handled with
// notifications from the RD. But this is not that bad as Sealing it will cause the
// final invalidation & it is no worse than the old code that also did not invalidate in this case
// Removed the not-empty check to allow invalidations in the case that the old dictionary
// is replaced with a new empty dictionary
if (oldValue != value)
{
TreeWalkHelper.InvalidateOnResourcesChange(null, this, new ResourcesChangeInfo(oldValue, value));
}
}
}
bool IQueryAmbient.IsAmbientPropertyAvailable(string propertyName)
{
// We want to make sure that StaticResource resolution checks the .Resources
// Ie. The Ambient search should look at Resources if it is set.
// Even if it wasn't set from XAML (eg. the Ctor (or derived Ctor) added stuff)
return (propertyName != "Resources" || HasResources);
}
/// <summary>
/// This method is used by TypeDescriptor to determine if this property should
/// be serialized.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool ShouldSerializeResources()
{
if (Resources == null || Resources.Count == 0)
{
return false;
}
return true;
}
/// <summary>
/// Searches for a resource with the passed resourceKey and returns it
/// </summary>
/// <remarks>
/// If the sources is not found on the called Element, the parent
/// chain is searched, using the logical tree.
/// </remarks>
/// <param name="resourceKey">Name of the resource</param>
/// <returns>The found resource. Null if not found.</returns>
public object FindResource(object resourceKey)
{
// Verify Context Access
// VerifyAccess();
ArgumentNullException.ThrowIfNull(resourceKey);
object resource = FrameworkElement.FindResourceInternal(null /* fe */, this, resourceKey);
if (resource == DependencyProperty.UnsetValue)
{
// Resource not found in parent chain, app or system
Helper.ResourceFailureThrow(resourceKey);
}
return resource;
}
/// <summary>
/// Searches for a resource with the passed resourceKey and returns it
/// </summary>
/// <remarks>
/// If the sources is not found on the called Element, the parent
/// chain is searched, using the logical tree.
/// </remarks>
/// <param name="resourceKey">Name of the resource</param>
/// <returns>The found resource. Null if not found.</returns>
public object TryFindResource(object resourceKey)
{
// Verify Context Access
// VerifyAccess();
ArgumentNullException.ThrowIfNull(resourceKey);
object resource = FrameworkElement.FindResourceInternal(null /* fe */, this, resourceKey);
if (resource == DependencyProperty.UnsetValue)
{
// Resource not found in parent chain, app or system
// This is where we translate DependencyProperty.UnsetValue to a null
resource = null;
}
return resource;
}
/// <summary>
/// Searches for a resource called name and sets up a resource reference
/// to it for the passed property.
/// </summary>
/// <param name="dp">Property to which the resource is bound</param>
/// <param name="name">Name of the resource</param>
public void SetResourceReference(
DependencyProperty dp,
object name)
{
// Set the value of the property to a ResourceReferenceExpression
SetValue(dp, new ResourceReferenceExpression(name));
// Set flag indicating that the current FrameworkContentElement instance
// has a property value set to a resource reference and hence must
// be invalidated on parent changed or resource property change events
HasResourceReference = true;
}
/// <summary>
/// Begins the given Storyboard as a non-controllable Storyboard and
/// the default handoff policy.
/// </summary>
public void BeginStoryboard(Storyboard storyboard)
{
BeginStoryboard(storyboard, HandoffBehavior.SnapshotAndReplace, false);
}
/// <summary>
/// Begins the given Storyboard as a non-controllable Storyboard but
/// with the given handoff policy.
/// </summary>
public void BeginStoryboard(Storyboard storyboard, HandoffBehavior handoffBehavior)
{
BeginStoryboard(storyboard, handoffBehavior, false);
}
/// <summary>
/// Begins the given Storyboard as a Storyboard with the given handoff
/// policy, and with the specified state for controllability.
/// </summary>
public void BeginStoryboard(Storyboard storyboard, HandoffBehavior handoffBehavior, bool isControllable)
{
ArgumentNullException.ThrowIfNull(storyboard);
// Storyboard.Begin is a public API and needs to be validating handoffBehavior anyway.
storyboard.Begin( this, handoffBehavior, isControllable );
}
/// <summary>
/// Allows subclasses to participate in property base value computation
/// </summary>
/// <param name="dp">Dependency property</param>
/// <param name="metadata">Type metadata of the property for the type</param>
/// <param name="newEntry">entry computed by base</param>
internal sealed override void EvaluateBaseValueCore(
DependencyProperty dp,
PropertyMetadata metadata,
ref EffectiveValueEntry newEntry)
{
if (dp == StyleProperty)
{
// If this is the first time that the StyleProperty
// is being fetched then mark it such
HasStyleEverBeenFetched = true;
// Clear the flags associated with the StyleProperty
HasImplicitStyleFromResources = false;
IsStyleSetFromGenerator = false;
}
GetRawValue(dp, metadata, ref newEntry);
Storyboard.GetComplexPathValue(this, dp, ref newEntry, metadata);
}
//[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647
internal void GetRawValue(DependencyProperty dp, PropertyMetadata metadata, ref EffectiveValueEntry entry)
{
// Check if value was resolved by base. If so, run it by animations
if ((entry.BaseValueSourceInternal == BaseValueSourceInternal.Local) &&
(entry.GetFlattenedEntry(RequestFlags.FullyResolved).Value != DependencyProperty.UnsetValue))
{
return;
}
//
// Try for container Style driven value
//
if (TemplateChildIndex != -1)
{
// This instance is in the template child chain of a Template.VisualTree,
// so we need to see if the Style has an applicable value.
//
// If the parent element's style is changing, this instance is
// in a visual tree that is being removed, and the value request
// is simply a result of tearing down some information in that
// tree (e.g. a BindingExpression). If so, just pretend there is no style (bug 991395).
if (GetValueFromTemplatedParent(dp, ref entry))
{
return;
}
}
//
// Try for Styled value
//
// Here are some of the implicit rules used by GetRawValue,
// while querying properties on the container.
// 1. Style property cannot be specified in a Style
// 2. Style property cannot be specified in a ThemeStyle
// 3. Style property cannot be specified in a Template
// 4. DefaultStyleKey property cannot be specified in a ThemeStyle
// 5. DefaultStyleKey property cannot be specified in a Template
// 6. Template property cannot be specified in a Template
if (dp != StyleProperty)
{
if (StyleHelper.GetValueFromStyleOrTemplate(new FrameworkObject(null, this), dp, ref entry))
{
return;
}
}
else
{
object source;
object implicitValue = FrameworkElement.FindImplicitStyleResource(this, this.GetType(), out source);
if (implicitValue != DependencyProperty.UnsetValue)
{
// Commented this because the implicit fetch could also return a DeferredDictionaryReference
// if (!(implicitValue is Style))
// {
// throw new InvalidOperationException(SR.Format(SR.InvalidImplicitStyleResource, this.GetType().Name, implicitValue));
// }
// This style has been fetched from resources
HasImplicitStyleFromResources = true;
entry.BaseValueSourceInternal = BaseValueSourceInternal.ImplicitReference;
entry.Value = implicitValue;
return;
}
}
//
// Try for Inherited value
//
FrameworkPropertyMetadata fmetadata = metadata as FrameworkPropertyMetadata;
// Note that for inheritable properties that override the default value a parent can impart
// its default value to the child even though the property may not have been set locally or
// via a style or template (ie. IsUsed flag would be false).
if (fmetadata != null)
{
if (fmetadata.Inherits)
{
//
// Inheritance
//
if (!TreeWalkHelper.SkipNext(InheritanceBehavior) || fmetadata.OverridesInheritanceBehavior == true)
{
// Used to terminate tree walk if a tree boundary is hit
InheritanceBehavior inheritanceBehavior;
FrameworkContentElement parentFCE;
FrameworkElement parentFE;
bool hasParent = FrameworkElement.GetFrameworkParent(this, out parentFE, out parentFCE);
while (hasParent)
{
bool inheritanceNode;
if (parentFE != null)
{
inheritanceNode = TreeWalkHelper.IsInheritanceNode(parentFE, dp, out inheritanceBehavior);
}
else // (parentFCE != null)
{
inheritanceNode = TreeWalkHelper.IsInheritanceNode(parentFCE, dp, out inheritanceBehavior);
}
// If the current node has SkipNow semantics then we do
// not need to lookup the inheritable value on it.
if (TreeWalkHelper.SkipNow(inheritanceBehavior))
{
break;
}
// Check if node is an inheritance node, if so, query it
if (inheritanceNode)
{
#region EventTracing
if (EventTrace.IsEnabled(EventTrace.Keyword.KeywordGeneral, EventTrace.Level.Verbose))
{
string TypeAndName = $"[{GetType().Name}]{dp.Name}";
EventTrace.EventProvider.TraceEvent(EventTrace.Event.WClientPropParentCheck,
EventTrace.Keyword.KeywordGeneral, EventTrace.Level.Verbose,
GetHashCode(), TypeAndName);
}
#endregion EventTracing
DependencyObject parentDO = parentFE;
if (parentDO == null)
{
parentDO = parentFCE;
}
EntryIndex entryIndex = parentDO.LookupEntry(dp.GlobalIndex);
entry = parentDO.GetValueEntry(
entryIndex,
dp,
fmetadata,
RequestFlags.SkipDefault | RequestFlags.DeferredReferences);
if (entry.Value != DependencyProperty.UnsetValue)
{
entry.BaseValueSourceInternal = BaseValueSourceInternal.Inherited;
}
return;
}
// If the current node has SkipNext semantics then we do
// not need to lookup the inheritable value on its parent.
if (TreeWalkHelper.SkipNext(inheritanceBehavior))
{
break;
}
// No boundary or inheritance node found, continue search
if (parentFE != null)
{
hasParent = FrameworkElement.GetFrameworkParent(parentFE, out parentFE, out parentFCE);
}
else
{
hasParent = FrameworkElement.GetFrameworkParent(parentFCE, out parentFE, out parentFCE);
}
}
}
}
}
// No value found.
Debug.Assert(entry.Value == DependencyProperty.UnsetValue);
}
// This FrameworkElement has been established to be a Template.VisualTree
// node of a parent object. Ask the TemplatedParent's Style object if
// they have a value for us.
private bool GetValueFromTemplatedParent(DependencyProperty dp, ref EffectiveValueEntry entry)
{
FrameworkTemplate frameworkTemplate = null;
FrameworkElement feTemplatedParent = (FrameworkElement)_templatedParent;
frameworkTemplate = feTemplatedParent.TemplateInternal;
if (frameworkTemplate != null)
{
return StyleHelper.GetValueFromTemplatedParent(
_templatedParent,
TemplateChildIndex,
new FrameworkObject(null, this),
dp,
ref frameworkTemplate.ChildRecordFromChildIndex,
frameworkTemplate.VisualTree,
ref entry);
}
return false;
}
// Like GetValueCore, except it returns the expression (if any) instead of its value
internal Expression GetExpressionCore(DependencyProperty dp, PropertyMetadata metadata)
{
this.IsRequestingExpression = true;
EffectiveValueEntry entry = new EffectiveValueEntry(dp);
entry.Value = DependencyProperty.UnsetValue;
this.EvaluateBaseValueCore(dp, metadata, ref entry);
this.IsRequestingExpression = false;
return entry.Value as Expression;
}
/// <summary>
/// Notification that a specified property has been changed
/// </summary>
/// <param name="e">EventArgs that contains the property, metadata, old value, and new value for this change</param>
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
DependencyProperty dp = e.Property;
// invalid during a VisualTreeChanged event
VisualDiagnostics.VerifyVisualTreeChange(this);
base.OnPropertyChanged(e);
if (e.IsAValueChange || e.IsASubPropertyChange)
{
//
// Try to fire the Loaded event on the root of the tree
// because for this case the OnParentChanged will not
// have a chance to fire the Loaded event.
//
if (dp != null && dp.OwnerType == typeof(PresentationSource) && dp.Name == "RootSource")
{
TryFireInitialized();
}
if (dp == FrameworkElement.NameProperty &&
EventTrace.IsEnabled(EventTrace.Keyword.KeywordGeneral, EventTrace.Level.Verbose))
{
EventTrace.EventProvider.TraceEvent(EventTrace.Event.PerfElementIDName, EventTrace.Keyword.KeywordGeneral, EventTrace.Level.Verbose,
PerfService.GetPerfElementID(this), GetType().Name, GetValue(dp));
}
//
// Invalidation propagation for Styles
//
// Regardless of metadata, the Style/DefaultStyleKey properties are never a trigger drivers
if (dp != StyleProperty && dp != DefaultStyleKeyProperty)
{
// Note even properties on non-container nodes within a template could be driving a trigger
if (TemplatedParent != null)
{
FrameworkElement feTemplatedParent = TemplatedParent as FrameworkElement;
FrameworkTemplate frameworkTemplate = feTemplatedParent.TemplateInternal;
StyleHelper.OnTriggerSourcePropertyInvalidated(null, frameworkTemplate, TemplatedParent, dp, e, false /*invalidateOnlyContainer*/,
ref frameworkTemplate.TriggerSourceRecordFromChildIndex, ref frameworkTemplate.PropertyTriggersWithActions, TemplateChildIndex /*sourceChildIndex*/);
}
// Do not validate Style during an invalidation if the Style was
// never used before (dependents do not need invalidation)
if (Style != null)
{
StyleHelper.OnTriggerSourcePropertyInvalidated(Style, null, this, dp, e, true /*invalidateOnlyContainer*/,
ref Style.TriggerSourceRecordFromChildIndex, ref Style.PropertyTriggersWithActions, 0 /*sourceChildId*/); // Style can only have triggers that are driven by properties on the container
}
// Do not validate Template during an invalidation if the Template was
// never used before (dependents do not need invalidation)
// There may be container dependents in the ThemeStyle. Invalidate them.
if (ThemeStyle != null && Style != ThemeStyle)
{
StyleHelper.OnTriggerSourcePropertyInvalidated(ThemeStyle, null, this, dp, e, true /*invalidateOnlyContainer*/,
ref ThemeStyle.TriggerSourceRecordFromChildIndex, ref ThemeStyle.PropertyTriggersWithActions, 0 /*sourceChildIndex*/); // ThemeStyle can only have triggers that are driven by properties on the container
}
}
}
FrameworkPropertyMetadata fmetadata = e.Metadata as FrameworkPropertyMetadata;
//
// Invalidation propagation for Groups and Inheritance
//
// Metadata must exist specifically stating propagate invalidation
// due to group or inheritance
if (fmetadata != null)
{
//
// Inheritance
//
if (fmetadata.Inherits)
{
// Invalidate Inheritable descendents only if instance is not a TreeSeparator
// or fmetadata.OverridesInheritanceBehavior is set to override separated tree behavior
if ((InheritanceBehavior == InheritanceBehavior.Default || fmetadata.OverridesInheritanceBehavior) &&
(!DependencyObject.IsTreeWalkOperation(e.OperationType) || PotentiallyHasMentees))
{
EffectiveValueEntry newEntry = e.NewEntry;
EffectiveValueEntry oldEntry = e.OldEntry;
if (oldEntry.BaseValueSourceInternal > newEntry.BaseValueSourceInternal)
{
// valuesource == Inherited && value == UnsetValue indicates that we are clearing the inherited value
newEntry = new EffectiveValueEntry(dp, BaseValueSourceInternal.Inherited);
}
else
{
newEntry = newEntry.GetFlattenedEntry(RequestFlags.FullyResolved);
newEntry.BaseValueSourceInternal = BaseValueSourceInternal.Inherited;
}
if (oldEntry.BaseValueSourceInternal != BaseValueSourceInternal.Default || oldEntry.HasModifiers)
{
oldEntry = oldEntry.GetFlattenedEntry(RequestFlags.FullyResolved);
oldEntry.BaseValueSourceInternal = BaseValueSourceInternal.Inherited;
}
else
{
// we use an empty EffectiveValueEntry as a signal that the old entry was the default value
oldEntry = new EffectiveValueEntry();
}
InheritablePropertyChangeInfo info =
new InheritablePropertyChangeInfo(
this,
dp,
oldEntry,
newEntry);
// Don't InvalidateTree if we're in the middle of doing it.
if (!DependencyObject.IsTreeWalkOperation(e.OperationType))
{
TreeWalkHelper.InvalidateOnInheritablePropertyChange(null, this, info, true);
}
// Notify mentees if they exist
if (PotentiallyHasMentees)
{
TreeWalkHelper.OnInheritedPropertyChanged(this, ref info, InheritanceBehavior);
}
}
}
}
}
/// <summary>
/// The DependencyProperty for the Name property.
/// </summary>
public static readonly DependencyProperty NameProperty =
FrameworkElement.NameProperty.AddOwner(
typeof(FrameworkContentElement),
new FrameworkPropertyMetadata(string.Empty));
/// <summary>
/// Name property.
/// </summary>
[MergableProperty(false)]
[Localizability(LocalizationCategory.NeverLocalize)] // cannot be localized
public string Name
{
get { return (string) GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
/// <summary>
/// The DependencyProperty for the Tag property.
/// </summary>
public static readonly DependencyProperty TagProperty =
FrameworkElement.TagProperty.AddOwner(
typeof(FrameworkContentElement),
new FrameworkPropertyMetadata((object) null));
/// <summary>
/// Tag property.
/// </summary>
public object Tag
{
get { return GetValue(TagProperty); }
set { SetValue(TagProperty, value); }
}
#region Language
/// <summary>
/// Language can be specified in xaml at any point using the xml language attribute xml:lang.
/// This will make the culture pertain to the scope of the element where it is applied. The
/// XmlLanguage names follow the RFC 3066 standard. For example, U.S. English is "en-US".
/// </summary>
static public readonly DependencyProperty LanguageProperty =
FrameworkElement.LanguageProperty.AddOwner(
typeof(FrameworkContentElement),
new FrameworkPropertyMetadata(
XmlLanguage.GetLanguage("en-US"),
FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsMeasure));
/// <summary>
/// Language can be specified in xaml at any point using the xml language attribute xml:lang.
/// This will make the culture pertain to the scope of the element where it is applied. The
/// XmlLanguage names follow the RFC 3066 standard. For example, U.S. English is "en-US".
/// </summary>
public XmlLanguage Language
{
get { return (XmlLanguage) GetValue(LanguageProperty); }
set { SetValue(LanguageProperty, value); }
}
#endregion Language
#region Input
/// <summary>
/// FocusVisualStyleProperty
/// </summary>
public static readonly DependencyProperty FocusVisualStyleProperty =
FrameworkElement.FocusVisualStyleProperty.AddOwner(typeof(FrameworkContentElement),
new FrameworkPropertyMetadata(FrameworkElement.DefaultFocusVisualStyle));
/// <summary>
/// FocusVisualStyle Property
/// </summary>
public Style FocusVisualStyle
{
get { return (Style) GetValue(FocusVisualStyleProperty); }
set { SetValue(FocusVisualStyleProperty, value); }
}
/// <summary>
/// CursorProperty
/// </summary>
public static readonly DependencyProperty CursorProperty =
FrameworkElement.CursorProperty.AddOwner(
typeof(FrameworkContentElement),
new FrameworkPropertyMetadata(
(object) null, // default value
0,
new PropertyChangedCallback(OnCursorChanged)));
/// <summary>
/// Cursor Property
/// </summary>
public System.Windows.Input.Cursor Cursor
{
get { return (System.Windows.Input.Cursor)GetValue(CursorProperty); }
set { SetValue(CursorProperty, value); }
}
// If the cursor is changed, we may need to set the actual cursor.
static private void OnCursorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkContentElement fce = ((FrameworkContentElement)d);
if(fce.IsMouseOver)
{
Mouse.UpdateCursor();
}
}
/// <summary>
/// ForceCursorProperty
/// </summary>
public static readonly DependencyProperty ForceCursorProperty =
FrameworkElement.ForceCursorProperty.AddOwner(
typeof(FrameworkContentElement),
new FrameworkPropertyMetadata(
BooleanBoxes.FalseBox, // default value
0,
new PropertyChangedCallback(OnForceCursorChanged)));
/// <summary>
/// ForceCursor Property
/// </summary>
public bool ForceCursor
{
get { return (bool) GetValue(ForceCursorProperty); }
set { SetValue(ForceCursorProperty, BooleanBoxes.Box(value)); }
}
// If the ForceCursor property changed, we may need to set the actual cursor.
static private void OnForceCursorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkContentElement fce = ((FrameworkContentElement)d);
if (fce.IsMouseOver)
{
Mouse.UpdateCursor();
}
}
private static void OnQueryCursor(object sender, QueryCursorEventArgs e)
{
FrameworkContentElement fce = (FrameworkContentElement) sender;
// We respond to querying the cursor by specifying the cursor set
// as a property on this element.
Cursor cursor = fce.Cursor;
if(cursor != null)
{
// We specify the cursor if the QueryCursor event is not
// handled by the time it gets to us, or if we are configured
// to force our cursor anyways. Since the QueryCursor event
// bubbles, this has the effect of overriding whatever cursor
// a child of ours specified.
if(!e.Handled || fce.ForceCursor)
{
e.Cursor = cursor;
e.Handled = true;
}
}
}
// Keyboard
/// <summary>
/// Request to move the focus from this element to another element
/// </summary>
/// <param name="request">
/// The direction that focus is to move.
/// </param>
/// <returns> Returns true if focus is moved successfully. Returns false if there is no next element</returns>
public sealed override bool MoveFocus(TraversalRequest request)
{
ArgumentNullException.ThrowIfNull(request);
return KeyboardNavigation.Current.Navigate(this, request);
}
/// <summary>
/// Request to predict the element that should receive focus relative to this element for a
/// given direction, without actually moving focus to it.
/// </summary>
/// <param name="direction">The direction for which focus should be predicted</param>
/// <returns>
/// Returns the next element that focus should move to for a given FocusNavigationDirection.
/// Returns null if focus cannot be moved relative to this element.
/// </returns>
public sealed override DependencyObject PredictFocus(FocusNavigationDirection direction)
{
return KeyboardNavigation.Current.PredictFocusedElement(this, direction);
}
/// <summary>
/// This method is invoked when the IsFocused property changes to true
/// </summary>
/// <param name="e">RoutedEventArgs</param>
protected override void OnGotFocus(RoutedEventArgs e)
{
// Scroll the element into view if currently focused
if (IsKeyboardFocused)
BringIntoView();
base.OnGotFocus(e);
}
private static void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
// This static class handler will get hit each time anybody gets hit with a tunnel that someone is getting focused.
// We're only interested when the element is getting focused is processing the event.
// NB: This will not do the right thing if the element rejects focus or does not want to be scrolled into view.
if (sender == e.OriginalSource)
{
FrameworkContentElement fce = (FrameworkContentElement)sender;
KeyboardNavigation.UpdateFocusedElement(fce);
KeyboardNavigation keyNav = KeyboardNavigation.Current;
KeyboardNavigation.ShowFocusVisual();
keyNav.UpdateActiveElement(fce);
}
}
private static void OnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
if (sender == e.OriginalSource)
{
KeyboardNavigation.Current.HideFocusVisual();
if (e.NewFocus == null)
{
KeyboardNavigation.Current.NotifyFocusChanged(sender, e);
}
}
}
/// <summary>
/// Attempts to bring this element into view by originating a RequestBringIntoView event.
/// </summary>
public void BringIntoView()
{
RequestBringIntoViewEventArgs args = new RequestBringIntoViewEventArgs(this, Rect.Empty);
args.RoutedEvent=FrameworkElement.RequestBringIntoViewEvent;
RaiseEvent(args);
}
#endregion Input
#region InputScope
/// <summary>
/// InputScope DependencyProperty
/// this is originally registered on InputMethod class
/// </summary>
public static readonly DependencyProperty InputScopeProperty =
InputMethod.InputScopeProperty.AddOwner(typeof(FrameworkContentElement),
new FrameworkPropertyMetadata((InputScope)null, // default value
FrameworkPropertyMetadataOptions.Inherits));
/// <summary>
/// InputScope Property accessor
/// </summary>
public InputScope InputScope
{
get { return (InputScope) GetValue(InputScopeProperty); }
set { SetValue(InputScopeProperty, value); }
}
#endregion InputScope
#region Data binding
/// <summary>
/// Add / Remove TargetUpdatedEvent handler
/// </summary>
public event EventHandler<DataTransferEventArgs> TargetUpdated
{
add { AddHandler(Binding.TargetUpdatedEvent, value); }
remove { RemoveHandler(Binding.TargetUpdatedEvent, value); }
}
/// <summary>
/// Add / Remove SourceUpdatedEvent handler
/// </summary>
public event EventHandler<DataTransferEventArgs> SourceUpdated
{
add { AddHandler(Binding.SourceUpdatedEvent, value); }
remove { RemoveHandler(Binding.SourceUpdatedEvent, value); }
}
/// <summary>
/// DataContext DependencyProperty
/// </summary>
public static readonly DependencyProperty DataContextProperty =
FrameworkElement.DataContextProperty.AddOwner(
typeof(FrameworkContentElement),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.Inherits,
new PropertyChangedCallback(OnDataContextChanged)));
/// <summary>
/// DataContextChanged event
/// </summary>
/// <remarks>
/// When an element's DataContext changes, all data-bound properties
/// (on this element or any other element) whose Binding use this
/// DataContext will change to reflect the new value. There is no
/// guarantee made about the order of these changes relative to the
/// raising of the DataContextChanged event. The changes can happen
/// before the event, after the event, or in any mixture.
/// </remarks>
public event DependencyPropertyChangedEventHandler DataContextChanged
{
add { EventHandlersStoreAdd(FrameworkElement.DataContextChangedKey, value); }
remove { EventHandlersStoreRemove(FrameworkElement.DataContextChangedKey, value); }
}
/// <summary>
/// DataContext Property
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Localizability(LocalizationCategory.NeverLocalize)]
public object DataContext
{
get { return GetValue(DataContextProperty); }
set { SetValue(DataContextProperty, value); }
}
private static void OnDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == BindingExpressionBase.DisconnectedItem)
return;
((FrameworkContentElement) d).RaiseDependencyPropertyChanged(FrameworkElement.DataContextChangedKey, e);
}
/// <summary>
/// Get the BindingExpression for the given property
/// </summary>
/// <param name="dp">DependencyProperty that represents the property</param>
/// <returns> BindingExpression if property is data-bound, null if it is not</returns>
public BindingExpression GetBindingExpression(DependencyProperty dp)
{
return BindingOperations.GetBindingExpression(this, dp);
}
/// <summary>
/// Attach a data Binding to a property
/// </summary>
/// <param name="dp">DependencyProperty that represents the property</param>
/// <param name="binding">description of Binding to attach</param>
public BindingExpressionBase SetBinding(DependencyProperty dp, BindingBase binding)
{
return BindingOperations.SetBinding(this, dp, binding);
}
/// <summary>
/// Convenience method. Create a BindingExpression and attach it.
/// Most fields of the BindingExpression get default values.
/// </summary>
/// <param name="dp">DependencyProperty that represents the property</param>
/// <param name="path">source path</param>
public BindingExpression SetBinding(DependencyProperty dp, string path)
{
return (BindingExpression)SetBinding(dp, new Binding(path));
}
/// <summary>
/// BindingGroup DependencyProperty
/// </summary>
public static readonly DependencyProperty BindingGroupProperty =
FrameworkElement.BindingGroupProperty.AddOwner(
typeof(FrameworkContentElement),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.Inherits));
/// <summary>
/// BindingGroup Property
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Localizability(LocalizationCategory.NeverLocalize)]
public BindingGroup BindingGroup
{
get { return (BindingGroup)GetValue(BindingGroupProperty); }
set { SetValue(BindingGroupProperty, value); }
}
#endregion Data binding
#region LogicalTree
/// <returns>
/// Returns a non-null value when some framework implementation
/// of this method has a non-visual parent connection,
/// </returns>
protected internal override DependencyObject GetUIParentCore()
{
return this._parent;
}
/// <summary>
/// Allows adjustment to the event source
/// </summary>
/// <remarks>
/// Subclasses must override this method
/// to be able to adjust the source during
/// route invocation <para/>
///
/// NOTE: Expected to return null when no
/// change is made to source
/// </remarks>
/// <param name="args">
/// Routed Event Args
/// </param>
/// <returns>
/// Returns new source
/// </returns>
internal override object AdjustEventSource(RoutedEventArgs args)
{
object source = null;
// As part of routing events through logical trees, we have
// to be careful about events that come to us from "foreign"
// trees. For example, the event could come from an element
// in our "implementation" visual tree, or from an element
// in a different logical tree all together.
//
// Note that we consider ourselves to be part of a logical tree
// if we have either a logical parent, or any logical children.
//
// BUGBUG: this misses "trees" that have only one logical node. No parents, no children.
if(_parent != null || HasLogicalChildren)
{
DependencyObject logicalSource = args.Source as DependencyObject;
if(logicalSource == null || !IsLogicalDescendent(logicalSource))
{
args.Source=this;
source = this;
}
}
return source;
}
// Allows adjustments to the branch source popped off the stack
internal virtual void AdjustBranchSource(RoutedEventArgs args)
{
}
internal virtual bool IgnoreModelParentBuildRoute(RoutedEventArgs args)
{
return false;
}
/// <summary>
/// Allows FrameworkElement to augment the
/// <see cref="EventRoute"/>
/// </summary>
/// <remarks>
/// NOTE: If this instance does not have a
/// visualParent but has a model parent
/// then route is built through the model
/// parent
/// </remarks>
/// <param name="route">
/// The <see cref="EventRoute"/> to be
/// augmented
/// </param>
/// <param name="args">
/// <see cref="RoutedEventArgs"/> for the
/// RoutedEvent to be raised post building
/// the route
/// </param>
/// <returns>
/// Whether or not the route should continue past the visual tree.
/// If this is true, and there are no more visual parents, the route
/// building code will call the GetUIParentCore method to find the
/// next non-visual parent.
/// </returns>
internal override sealed bool BuildRouteCore(EventRoute route, RoutedEventArgs args)
{
bool continuePastCoreTree = false;
// Verify Context Access
// VerifyAccess();
DependencyObject visualParent = (DependencyObject) ContentOperations.GetParent(this);
DependencyObject modelParent = this._parent;
// FrameworkElement extends the basic event routing strategy by
// introducing the concept of a logical tree. When an event
// passes through an element in a logical tree, the source of
// the event needs to change to the leaf-most node in the same
// logical tree that is in the route.
// Check the route to see if we are returning into a logical tree
// that we left before. If so, restore the source of the event to
// be the source that it was when we left the logical tree.
DependencyObject branchNode = route.PeekBranchNode() as DependencyObject;
if (branchNode != null && IsLogicalDescendent(branchNode))
{
// We keep the most recent source in the event args. Note that
// this is only for our consumption. Once the event is raised,
// it will use the source information in the route.
args.Source = (route.PeekBranchSource());
AdjustBranchSource(args);
route.AddSource(args.Source);
// By popping the branch node we will also be setting the source
// in the event route.
route.PopBranchNode();
// Add intermediate ContentElements to the route
FrameworkElement.AddIntermediateElementsToRoute(this, route, args, LogicalTreeHelper.GetParent(branchNode));
}
// Check if the next element in the route is in a different
// logical tree.
if (!IgnoreModelParentBuildRoute(args))
{
// If there is no visual parent, route via the model tree.
if (visualParent == null)
{
continuePastCoreTree = modelParent != null;
}
else if(modelParent != null)
{
// If there is a model parent, record the branch node.
route.PushBranchNode(this, args.Source);
// The source is going to be the visual parent, which
// could live in a different logical tree.
args.Source = (visualParent);
}
}
return continuePastCoreTree;
}
/// <summary>
/// Add Style TargetType and FEF EventHandlers to the EventRoute
/// </summary>
internal override void AddToEventRouteCore(EventRoute route, RoutedEventArgs args)
{
FrameworkElement.AddStyleHandlersToEventRoute(null, this, route, args);
}
// Returns if the given child instance is a logical descendent
private bool IsLogicalDescendent(DependencyObject child)
{
while (child != null)
{
if (child == this)
{
return true;
}
child = LogicalTreeHelper.GetParent(child);
}
return false;
}
internal override bool InvalidateAutomationAncestorsCore(Stack<DependencyObject> branchNodeStack, out bool continuePastCoreTree)
{
bool continueInvalidation = true;
continuePastCoreTree = false;
DependencyObject visualParent = (DependencyObject) ContentOperations.GetParent(this);
DependencyObject modelParent = this._parent;
DependencyObject branchNode = branchNodeStack.Count > 0 ? branchNodeStack.Peek() : null;
if (branchNode != null && IsLogicalDescendent(branchNode))
{
branchNodeStack.Pop();
continueInvalidation = FrameworkElement.InvalidateAutomationIntermediateElements(this, LogicalTreeHelper.GetParent(branchNode));
}
// If there is no visual parent, route via the model tree.
if (visualParent == null)
{
continuePastCoreTree = modelParent != null;
}
else if(modelParent != null)
{
// If there is a model parent, record the branch node.
branchNodeStack.Push(this);
}
return continueInvalidation;
}
/// <summary>
/// Invoked when ancestor is changed. This is invoked after
/// the ancestor has changed, and the purpose is to allow elements to
/// perform actions based on the changed ancestor.
/// </summary>
internal virtual void OnAncestorChanged()
{
}
/// <summary>
/// OnContentParentChanged is called when the parent of the content element is changed.
/// </summary>
/// <param name="oldParent">Old parent or null if the content element did not have a parent before.</param>
internal override void OnContentParentChanged(DependencyObject oldParent)
{
DependencyObject newParent = ContentOperations.GetParent(this);
// Initialize, if not already done
TryFireInitialized();
base.OnContentParentChanged(oldParent);
}
/// <summary>
/// Indicates the current mode of lookup for both inheritance and resources.
/// </summary>
/// <remarks>
/// Used in property inheritence and reverse
/// inheritence and resource lookup to stop at
/// logical tree boundaries
///
/// It is also used by designers such as Sparkle to
/// skip past the app resources directly to the theme.
/// They are expected to merge in the client's app
/// resources via the MergedDictionaries feature on
/// root element of the tree.
///
/// NOTE: Property can be set only when the
/// instance is not yet hooked to the tree. This
/// is to encourage setting it at construction time.
/// If we didn't restrict it to (roughly) construction
/// time, we would have to take the complexity of
/// firing property invalidations when the flag was
/// changed.
/// </remarks>
internal InheritanceBehavior InheritanceBehavior
{
get
{
Debug.Assert((uint)InternalFlags.InheritanceBehavior0 == 0x08);
Debug.Assert((uint)InternalFlags.InheritanceBehavior1 == 0x10);
Debug.Assert((uint)InternalFlags.InheritanceBehavior2 == 0x20);
const uint inheritanceBehaviorMask =
(uint)InternalFlags.InheritanceBehavior0 +
(uint)InternalFlags.InheritanceBehavior1 +
(uint)InternalFlags.InheritanceBehavior2;
uint inheritanceBehavior = ((uint)_flags & inheritanceBehaviorMask) >> 3;
return (InheritanceBehavior)inheritanceBehavior;
}
set
{
Debug.Assert((uint)InternalFlags.InheritanceBehavior0 == 0x08);
Debug.Assert((uint)InternalFlags.InheritanceBehavior1 == 0x10);
Debug.Assert((uint)InternalFlags.InheritanceBehavior2 == 0x20);
const uint inheritanceBehaviorMask =
(uint)InternalFlags.InheritanceBehavior0 +
(uint)InternalFlags.InheritanceBehavior1 +
(uint)InternalFlags.InheritanceBehavior2;
if (!this.IsInitialized)
{
if ((uint)value < 0 ||
(uint)value > (uint)InheritanceBehavior.SkipAllNext)
{
throw new InvalidEnumArgumentException("value", (int)value, typeof(InheritanceBehavior));
}
uint inheritanceBehavior = (uint)value << 3;
_flags = (InternalFlags)((inheritanceBehavior & inheritanceBehaviorMask) | (((uint)_flags) & ~inheritanceBehaviorMask));
if (_parent != null)
{
// This means that we are in the process of xaml parsing:
// an instance of FCE has been created and added to a parent,
// but no children yet added to it (otherwise it would be initialized already
// and we would not be allowed to change InheritanceBehavior).
// So we need to re-calculate properties accounting for the new
// inheritance behavior.
// This must have no performance effect as the subtree of this
// element is empty (no children yet added).
TreeWalkHelper.InvalidateOnTreeChange(/*fe:*/null, /*fce:*/this, _parent, true);
}
}
else
{
throw new InvalidOperationException(SR.Illegal_InheritanceBehaviorSettor);
}
}
}
#endregion LogicalTree
#region ISupportInitialize
/// <summary>
/// Initialization of this element is about to begin
/// </summary>
public virtual void BeginInit()
{
// Nested BeginInits on the same instance aren't permitted
if (ReadInternalFlag(InternalFlags.InitPending))
{
throw new InvalidOperationException(SR.NestedBeginInitNotSupported);
}
// Mark the element as pending initialization
WriteInternalFlag(InternalFlags.InitPending, true);
}
/// <summary>
/// Initialization of this element has completed
/// </summary>
public virtual void EndInit()
{
// Every EndInit must be preceeded by a BeginInit
if (!ReadInternalFlag(InternalFlags.InitPending))
{
throw new InvalidOperationException(SR.EndInitWithoutBeginInitNotSupported);
}
// Reset the pending flag
WriteInternalFlag(InternalFlags.InitPending, false);
// Mark the element initialized and fire Initialized event
// (eg. tree building via parser)
TryFireInitialized();
}
/// <summary>
/// Has this element been initialized
/// </summary>
/// <remarks>
/// True if either EndInit or OnParentChanged were called
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public bool IsInitialized
{
get { return ReadInternalFlag(InternalFlags.IsInitialized); }
}
/// <summary>
/// This clr event is fired when
/// <see cref="IsInitialized"/>
/// becomes true
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public event EventHandler Initialized
{
add { EventHandlersStoreAdd(FrameworkElement.InitializedKey, value); }
remove { EventHandlersStoreRemove(FrameworkElement.InitializedKey, value); }
}
/// <summary>
/// This virtual method in called when IsInitialized is set to true and it raises an Initialized event
/// </summary>
protected virtual void OnInitialized(EventArgs e)
{
// Need to update the StyleProperty so that we can pickup
// the implicit style if it hasn't already been fetched
if (!HasStyleEverBeenFetched)
{
UpdateStyleProperty();
}
// Need to update the ThemeStyleProperty so that we can pickup
// the implicit style if it hasn't already been fetched
if (!HasThemeStyleEverBeenFetched)
{
UpdateThemeStyleProperty();
}
RaiseInitialized(FrameworkElement.InitializedKey, e);
}
// Helper method that tries to set IsInitialized to true
// and Fire the Initialized event
// This method can be invoked from two locations
// 1> EndInit
// 2> OnParentChanged
private void TryFireInitialized()
{
if (!ReadInternalFlag(InternalFlags.InitPending) &&
!ReadInternalFlag(InternalFlags.IsInitialized))
{
WriteInternalFlag(InternalFlags.IsInitialized, true);
OnInitialized(EventArgs.Empty);
}
}
// Helper method to retrieve and fire Clr Event handlers for Initialized event
private void RaiseInitialized(EventPrivateKey key, EventArgs e)
{
EventHandlersStore store = EventHandlersStore;
if (store != null)
{
Delegate handler = store.Get(key);
if (handler != null)
{
((EventHandler)handler)(this, e);
}
}
}
#endregion ISupportInitialize
#region LoadedAndUnloadedEvents
/// <summary>
/// This DP is set on the root of a sub-tree that is about to receive a broadcast Loaded event
/// This DP is cleared when the Loaded event is either fired or cancelled for some reason
/// </summary>
private static readonly DependencyProperty LoadedPendingProperty
= FrameworkElement.LoadedPendingProperty.AddOwner(typeof(FrameworkContentElement));
/// <summary>
/// This DP is set on the root of a sub-tree that is about to receive a broadcast Unloaded event
/// This DP is cleared when the Unloaded event is either fired or cancelled for some reason
/// </summary>
private static readonly DependencyProperty UnloadedPendingProperty
= FrameworkElement.UnloadedPendingProperty.AddOwner(typeof(FrameworkContentElement));
/// <summary>
/// Turns true when this element is attached to a tree and is laid out and rendered.
/// Turns false when the element gets detached from a loaded tree
/// </summary>
public bool IsLoaded
{
get
{
object[] loadedPending = LoadedPending;
object[] unloadedPending = UnloadedPending;
if (loadedPending == null && unloadedPending == null)
{
// The HasHandler flags are used for validation of the IsLoaded flag
if (SubtreeHasLoadedChangeHandler)
{
// The IsLoaded flag is valid
return IsLoadedCache;
}
else
{
// IsLoaded flag isn't valid
return BroadcastEventHelper.IsParentLoaded(this);
}
}
else
{
// This is the case where we might be
// 1. Pending Unloaded only
// In this case we are already Loaded
// 2. Pending Loaded only
// In this case we are not Loaded yet
// 3. Pending both Loaded and Unloaded
// We can get to this state only when Unloaded operation preceeds Loaded.
// If Loaded preceeded Unloaded then it is sure to have been cancelled
// out by the latter.
return (unloadedPending != null);
}
}
}
/// <summary>
/// Loaded RoutedEvent
/// </summary>
public static readonly RoutedEvent LoadedEvent = FrameworkElement.LoadedEvent.AddOwner( typeof(FrameworkContentElement));
/// <summary>
/// This event is fired when the element is laid out, rendered and ready for interaction
/// </summary>
public event RoutedEventHandler Loaded
{
add
{
AddHandler(FrameworkElement.LoadedEvent, value, false);
}
remove
{
RemoveHandler(FrameworkElement.LoadedEvent, value);
}
}
/// <summary>
/// Helper that will set the IsLoaded flag and Raise the Loaded event
/// </summary>
internal void OnLoaded(RoutedEventArgs args)
{
RaiseEvent(args);
}
/// <summary>
/// Unloaded RoutedEvent
/// </summary>
public static readonly RoutedEvent UnloadedEvent = FrameworkElement.UnloadedEvent.AddOwner( typeof(FrameworkContentElement));
/// <summary>
/// This clr event is fired when this element is detached form a loaded tree
/// </summary>
public event RoutedEventHandler Unloaded
{
add
{
AddHandler(FrameworkElement.UnloadedEvent, value, false);
}
remove
{
RemoveHandler(FrameworkElement.UnloadedEvent, value);
}
}
/// <summary>
/// Helper that will reset the IsLoaded flag and Raise the Unloaded event
/// </summary>
internal void OnUnloaded(RoutedEventArgs args)
{
RaiseEvent(args);
}
/// <summary>
/// Notifies subclass of a new routed event handler. Note that this is
/// called once for each handler added, but OnRemoveHandler is only called
/// on the last removal.
/// </summary>
internal override void OnAddHandler(
RoutedEvent routedEvent,
Delegate handler)
{
if (routedEvent == LoadedEvent || routedEvent == UnloadedEvent)
{
BroadcastEventHelper.AddHasLoadedChangeHandlerFlagInAncestry(this);
}
}
/// <summary>
/// Notifies subclass of an event for which a handler has been removed.
/// </summary>
internal override void OnRemoveHandler(
RoutedEvent routedEvent,
Delegate handler)
{
// We only care about Loaded & Unloaded events
if (routedEvent != LoadedEvent && routedEvent != UnloadedEvent)
return;
if (!ThisHasLoadedChangeEventHandler)
{
BroadcastEventHelper.RemoveHasLoadedChangeHandlerFlagInAncestry(this);
}
}
// Helper method to retrieve and fire Clr Event handlers
internal void RaiseClrEvent(EventPrivateKey key, EventArgs args)
{
EventHandlersStore store = EventHandlersStore;
if (store != null)
{
Delegate handler = store.Get(key);
if (handler != null)
{
((EventHandler)handler)(this, args);
}
}
}
#endregion LoadedAndUnloadedEvents
#region PopupControlService
/// <summary>
/// The DependencyProperty for the ToolTip property
/// </summary>
public static readonly DependencyProperty ToolTipProperty =
ToolTipService.ToolTipProperty.AddOwner(typeof(FrameworkContentElement));
/// <summary>
/// The ToolTip for the element.
/// If the value is of type ToolTip, then that is the ToolTip that will be used.
/// If the value is of any other type, then that value will be used
/// as the content for a ToolTip provided by the system. Refer to ToolTipService
/// for attached properties to customize the ToolTip.
/// </summary>
[Bindable(true), Category("Appearance")]
public object ToolTip
{
get
{
return ToolTipService.GetToolTip(this);
}
set
{
ToolTipService.SetToolTip(this, value);
}
}
/// <summary>
/// The DependencyProperty for the Contextmenu property
/// </summary>
public static readonly DependencyProperty ContextMenuProperty =
ContextMenuService.ContextMenuProperty.AddOwner(typeof(FrameworkContentElement),
new FrameworkPropertyMetadata((ContextMenu) null));
/// <summary>
/// The ContextMenu data set on this element. Can be any type that can be converted to a UIElement.
/// </summary>
public ContextMenu ContextMenu
{
get
{
return (ContextMenu)GetValue(ContextMenuProperty);
}
set
{
SetValue(ContextMenuProperty, value);
}
}
/// <summary>
/// The RoutedEvent for the ToolTipOpening event.
/// </summary>
public static readonly RoutedEvent ToolTipOpeningEvent = ToolTipService.ToolTipOpeningEvent.AddOwner(typeof(FrameworkContentElement));
/// <summary>
/// An event that fires just before a ToolTip should be opened.
/// This event does not fire if the value of ToolTip is null or unset.
///
/// To manually open and close ToolTips, set the value of ToolTip to a non-null value
/// and then mark this event as handled.
///
/// To delay loading the actual ToolTip value, set the value of the ToolTip property to
/// any value (you can also use it as a tag) and then set the value to the actual value
/// in a handler for this event. Do not mark the event as handled if the system provided
/// functionality for showing or hiding the ToolTip is desired.
/// </summary>
public event ToolTipEventHandler ToolTipOpening
{
add { AddHandler(ToolTipOpeningEvent, value); }
remove { RemoveHandler(ToolTipOpeningEvent, value); }
}
private static void OnToolTipOpeningThunk(object sender, ToolTipEventArgs e)
{
((FrameworkContentElement)sender).OnToolTipOpening(e);
}
/// <summary>
/// Called when the ToolTipOpening event fires.
/// Allows subclasses to add functionality without having to attach
/// an individual handler.
/// </summary>
/// <param name="e">Event arguments</param>
protected virtual void OnToolTipOpening(ToolTipEventArgs e)
{
}
/// <summary>
/// The RoutedEvent for the ToolTipClosing event.
/// </summary>
public static readonly RoutedEvent ToolTipClosingEvent = ToolTipService.ToolTipClosingEvent.AddOwner(typeof(FrameworkContentElement));
/// <summary>
/// An event that fires just before a ToolTip should be closed.
/// This event will only fire if there was a preceding ToolTipOpening event.
///
/// To manually close a ToolTip and not use the system behavior, mark this event as handled.
/// </summary>
public event ToolTipEventHandler ToolTipClosing
{
add { AddHandler(ToolTipClosingEvent, value); }
remove { RemoveHandler(ToolTipClosingEvent, value); }
}
private static void OnToolTipClosingThunk(object sender, ToolTipEventArgs e)
{
((FrameworkContentElement)sender).OnToolTipClosing(e);
}
/// <summary>
/// Called when the ToolTipClosing event fires.
/// Allows subclasses to add functionality without having to attach
/// an individual handler.
/// </summary>
/// <param name="e">Event arguments</param>
protected virtual void OnToolTipClosing(ToolTipEventArgs e)
{
}
/// <summary>
/// RoutedEvent for the ContextMenuOpening event.
/// </summary>
public static readonly RoutedEvent ContextMenuOpeningEvent = ContextMenuService.ContextMenuOpeningEvent.AddOwner(typeof(FrameworkContentElement));
/// <summary>
/// An event that fires just before a ContextMenu should be opened.
///
/// To manually open and close ContextMenus, mark this event as handled.
/// Otherwise, the value of the the ContextMenu property will be used
/// to automatically open a ContextMenu.
/// </summary>
public event ContextMenuEventHandler ContextMenuOpening
{
add { AddHandler(ContextMenuOpeningEvent, value); }
remove { RemoveHandler(ContextMenuOpeningEvent, value); }
}
private static void OnContextMenuOpeningThunk(object sender, ContextMenuEventArgs e)
{
((FrameworkContentElement)sender).OnContextMenuOpening(e);
}
/// <summary>
/// Called when ContextMenuOpening is raised on this element.
/// </summary>
/// <param name="e">Event arguments</param>
protected virtual void OnContextMenuOpening(ContextMenuEventArgs e)
{
}
/// <summary>
/// RoutedEvent for the ContextMenuClosing event.
/// </summary>
public static readonly RoutedEvent ContextMenuClosingEvent = ContextMenuService.ContextMenuClosingEvent.AddOwner(typeof(FrameworkContentElement));
/// <summary>
/// An event that fires just as a ContextMenu closes.
/// </summary>
public event ContextMenuEventHandler ContextMenuClosing
{
add { AddHandler(ContextMenuClosingEvent, value); }
remove { RemoveHandler(ContextMenuClosingEvent, value); }
}
private static void OnContextMenuClosingThunk(object sender, ContextMenuEventArgs e)
{
((FrameworkContentElement)sender).OnContextMenuClosing(e);
}
/// <summary>
/// Called when ContextMenuClosing is raised on this element.
/// </summary>
/// <param name="e">Event arguments</param>
protected virtual void OnContextMenuClosing(ContextMenuEventArgs e)
{
}
#endregion
// This has to be virtual, since there is no concept of "core" content children,
// so we have no choice by to rely on FrameworkContentElement to use logical
// children instead.
internal override void InvalidateForceInheritPropertyOnChildren(DependencyProperty property)
{
IEnumerator enumerator = LogicalChildren;
if(enumerator != null)
{
while(enumerator.MoveNext())
{
DependencyObject child =enumerator.Current as DependencyObject;
if(child != null)
{
// CODE REVIEW (dwaynen)
//
// We assume we will only ever have a UIElement or a ContentElement
// as a child of a FrameworkContentElement. (Not a raw Visual.)
child.CoerceValue(property);
}
}
}
}
// Helper method to retrieve and fire Clr Event handlers for DependencyPropertyChanged event
private void RaiseDependencyPropertyChanged(EventPrivateKey key, DependencyPropertyChangedEventArgs args)
{
EventHandlersStore store = EventHandlersStore;
if (store != null)
{
Delegate handler = store.Get(key);
if (handler != null)
{
((DependencyPropertyChangedEventHandler)handler)(this, args);
}
}
}
private void EventHandlersStoreAdd(EventPrivateKey key, Delegate handler)
{
EnsureEventHandlersStore();
EventHandlersStore.Add(key, handler);
}
private void EventHandlersStoreRemove(EventPrivateKey key, Delegate handler)
{
EventHandlersStore store = EventHandlersStore;
if (store != null)
{
store.Remove(key, handler);
}
}
// Gettor and Settor for flag that indicates
// if this instance has some property values
// that are set to a resource reference
internal bool HasResourceReference
{
get { return ReadInternalFlag(InternalFlags.HasResourceReferences); }
set { WriteInternalFlag(InternalFlags.HasResourceReferences, value); }
}
internal bool IsLogicalChildrenIterationInProgress
{
get { return ReadInternalFlag(InternalFlags.IsLogicalChildrenIterationInProgress); }
set { WriteInternalFlag(InternalFlags.IsLogicalChildrenIterationInProgress, value); }
}
internal bool SubtreeHasLoadedChangeHandler
{
get { return ReadInternalFlag2(InternalFlags2.TreeHasLoadedChangeHandler); }
set { WriteInternalFlag2(InternalFlags2.TreeHasLoadedChangeHandler, value); }
}
internal bool IsLoadedCache
{
get { return ReadInternalFlag2(InternalFlags2.IsLoadedCache); }
set { WriteInternalFlag2(InternalFlags2.IsLoadedCache, value); }
}
internal bool IsParentAnFE
{
get { return ReadInternalFlag2(InternalFlags2.IsParentAnFE); }
set { WriteInternalFlag2(InternalFlags2.IsParentAnFE, value); }
}
internal bool IsTemplatedParentAnFE
{
get { return ReadInternalFlag2(InternalFlags2.IsTemplatedParentAnFE); }
set { WriteInternalFlag2(InternalFlags2.IsTemplatedParentAnFE, value); }
}
internal bool HasLogicalChildren
{
get { return ReadInternalFlag(InternalFlags.HasLogicalChildren); }
set { WriteInternalFlag(InternalFlags.HasLogicalChildren, value); }
}
// See comment on FrameworkElement.TemplateChildIndex
internal int TemplateChildIndex
{
get
{
uint childIndex = (((uint)_flags2) & 0xFFFF);
if (childIndex == 0xFFFF)
{
return -1;
}
else
{
return (int)childIndex;
}
}
set
{
// We store TemplateChildIndex as a 16-bit integer with 0xFFFF meaning "-1".
// Thus we support any indices in the range [-1, 65535).
if (value < -1 || value >= 0xFFFF)
{
throw new ArgumentOutOfRangeException("value", SR.TemplateChildIndexOutOfRange);
}
uint childIndex = (value == -1) ? 0xFFFF : (uint)value;
_flags2 = (InternalFlags2)(childIndex | (((uint)_flags2) & 0xFFFF0000));
}
}
internal bool IsRequestingExpression
{
get { return ReadInternalFlag2(InternalFlags2.IsRequestingExpression); }
set { WriteInternalFlag2(InternalFlags2.IsRequestingExpression, value); }
}
// Extracts the required flag and returns
// bool to indicate if it is set or unset
internal bool ReadInternalFlag(InternalFlags reqFlag)
{
return (_flags & reqFlag) != 0;
}
internal bool ReadInternalFlag2(InternalFlags2 reqFlag)
{
return (_flags2 & reqFlag) != 0;
}
// Sets or Unsets the required flag based on
// the bool argument
internal void WriteInternalFlag(InternalFlags reqFlag, bool set)
{
if (set)
{
_flags |= reqFlag;
}
else
{
_flags &= (~reqFlag);
}
}
internal void WriteInternalFlag2(InternalFlags2 reqFlag, bool set)
{
if (set)
{
_flags2 |= reqFlag;
}
else
{
_flags2 &= ~reqFlag;
}
}
// Style/Template state (internals maintained by Style)
private Style _styleCache;
// ThemeStyle used only when a DefaultStyleKey is specified
private Style _themeStyleCache;
// See FrameworkElement (who also have these) for details on these values.
internal DependencyObject _templatedParent; // Non-null if this object was created as a result of a Template.VisualTree
// Resources dictionary
private static readonly UncommonField<ResourceDictionary> ResourcesField = FrameworkElement.ResourcesField;
private InternalFlags _flags = 0; // field used to store various flags such as HasResourceReferences, etc.
private InternalFlags2 _flags2 = InternalFlags2.Default; // field used to store various flags such as HasResourceReferences, etc.
}
}
|