File: System\Windows\ContentElement.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationCore\PresentationCore.csproj (PresentationCore)
// 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 MS.Internal;
using MS.Internal.Interop;
using MS.Internal.KnownBoxes;
using MS.Internal.PresentationCore;
using MS.Utility;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Security;
using System.Windows.Automation;
using System.Windows.Automation.Peers;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media.Animation;
using System.Windows.Threading;
 
using SR=MS.Internal.PresentationCore.SR;
 
namespace System.Windows
{
    /// <summary>
    ///     ContentElement Class is a DependencyObject with IFE - input, focus, and events
    /// </summary>
    /// <ExternalAPI/>
    public partial class ContentElement : DependencyObject, IInputElement, IAnimatable
    {
        #region Construction
 
        /// <summary>
        ///     Static Constructor for ContentElement
        /// </summary>
        static ContentElement()
        {
            UIElement.RegisterEvents(typeof(ContentElement));
            RegisterProperties();
 
            UIElement.IsFocusedPropertyKey.OverrideMetadata(
                typeof(ContentElement),
                new PropertyMetadata(
                    BooleanBoxes.FalseBox, // default value
                    new PropertyChangedCallback(IsFocused_Changed)));
        }
                
        #endregion Construction
 
        #region DependencyObject
 
        #endregion
 
        /// <summary>
        /// Helper, gives the UIParent under control of which
        /// the OnMeasure or OnArrange are currently called.
        /// This may be implemented as a tree walk up until
        /// LayoutElement is found.
        /// </summary>
        internal DependencyObject GetUIParent()
        {
            return GetUIParent(false);
        }
 
        internal DependencyObject GetUIParent(bool continuePastVisualTree)
        {
            DependencyObject e = null;
 
            // Try to find a UIElement parent in the visual ancestry.
            e = InputElement.GetContainingInputElement(_parent) as DependencyObject;
 
            // If there was no InputElement parent in the visual ancestry,
            // check along the logical branch.
            if(e == null && continuePastVisualTree)
            {
                DependencyObject doParent = GetUIParentCore();
                e = InputElement.GetContainingInputElement(doParent) as DependencyObject;
            }
 
            return e;
        }
 
        /// <summary>
        ///     Called to get the UI parent of this element when there is
        ///     no visual parent.
        /// </summary>
        /// <returns>
        ///     Returns a non-null value when some framework implementation
        ///     of this method has a non-visual parent connection,
        /// </returns>
        protected virtual internal DependencyObject GetUIParentCore()
        {
            return null;
        }
 
        internal DependencyObject Parent
        {
            get
            {
                return _parent;
            }
        }
 
        /// <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 virtual void OnContentParentChanged(DependencyObject oldParent)
        {
            SynchronizeReverseInheritPropertyFlags(oldParent, true);
        }
 
        #region Automation
 
        /// <summary>
        /// Called by the Automation infrastructure when AutomationPeer
        /// is requested for this element. The element can return null or
        /// the instance of AutomationPeer-derived clas, if it supports UI Automation
        /// </summary>
        protected virtual AutomationPeer OnCreateAutomationPeer() { return null; }
 
        /// <summary>
        /// Called by the Automation infrastructure or Control author
        /// to make sure the AutomationPeer is created. The element may
        /// create AP or return null, depending on OnCreateAutomationPeer override.
        /// </summary>
        internal AutomationPeer CreateAutomationPeer()
        {
            VerifyAccess(); //this will ensure the AP is created in the right context
 
            AutomationPeer ap = null;
 
            if (HasAutomationPeer)
            {
                ap = AutomationPeerField.GetValue(this);
            }
            else
            {
                ap = OnCreateAutomationPeer();
 
                if (ap != null)
                {
                    AutomationPeerField.SetValue(this, ap);
                    HasAutomationPeer = true;
                }
            }
            return ap;
        }
 
        /// <summary>
        /// Returns AutomationPeer if one exists.
        /// The AutomationPeer may not exist if not yet created by Automation infrastructure
        /// or if this element is not supposed to have one.
        /// </summary>
        internal AutomationPeer GetAutomationPeer()
        {
            VerifyAccess();
 
            if (HasAutomationPeer)
                return AutomationPeerField.GetValue(this);
 
            return null;
        }
 
        // If this element is currently listening to synchronized input, add a pre-opportunity handler to keep track of event routed through this element.
        internal void AddSynchronizedInputPreOpportunityHandler(EventRoute route, RoutedEventArgs args)
        {
            if (InputManager.IsSynchronizedInput)
            {
                if (SynchronizedInputHelper.IsListening(this, args))
                {
                    RoutedEventHandler eventHandler = new RoutedEventHandler(this.SynchronizedInputPreOpportunityHandler);
                    SynchronizedInputHelper.AddHandlerToRoute(this, route, eventHandler, false);
                }
            }
        }
 
        // If this element is currently listening to synchronized input, add a handler to post process the synchronized input otherwise
        // add a synchronized input pre-opportunity handler from parent if parent is listening.
        internal void AddSynchronizedInputPostOpportunityHandler(EventRoute route, RoutedEventArgs args)
        {
            if (InputManager.IsSynchronizedInput)
            {
                if (SynchronizedInputHelper.IsListening(this, args))
                {
                    RoutedEventHandler eventHandler = new RoutedEventHandler(this.SynchronizedInputPostOpportunityHandler);
                    SynchronizedInputHelper.AddHandlerToRoute(this, route, eventHandler, true);
                }
                else
                {
                    // Add a preview handler from the parent.
                    SynchronizedInputHelper.AddParentPreOpportunityHandler(this, route, args);
                }
            }
 
        }
 
        // This event handler to be called before all the class & instance handlers for this element.
        internal void SynchronizedInputPreOpportunityHandler(object sender, RoutedEventArgs args)
        {
            if (!args.Handled)
            {
                SynchronizedInputHelper.PreOpportunityHandler(sender, args);
            }
        }
        // This event handler to be called after class & instance handlers for this element.
        internal void SynchronizedInputPostOpportunityHandler(object sender, RoutedEventArgs args)
        {
            if (args.Handled && (InputManager.SynchronizedInputState == SynchronizedInputStates.HadOpportunity))
            {
                SynchronizedInputHelper.PostOpportunityHandler(sender, args);
            }
        }
 
 
        // Called by automation peer, when called this element will be the listening element for synchronized input.   
        internal bool StartListeningSynchronizedInput(SynchronizedInputType inputType)
        {
            if (InputManager.IsSynchronizedInput)
            {
                return false;
            }
            else
            {
                InputManager.StartListeningSynchronizedInput(this, inputType);
                return true;
            }
        }
 
        // When called, input processing will return to normal mode.
        internal void CancelSynchronizedInput()
        {
            InputManager.CancelSynchronizedInput();
        }                     
        
        #endregion Automation
 
        #region Input
 
        /// <summary>
        ///     A property indicating if the mouse is over this element or not.
        /// </summary>
        public bool IsMouseDirectlyOver
        {
            get
            {
                // We do not return the cached value of reverse-inherited seed properties.
                //
                // The cached value is only used internally to detect a "change".
                //
                // More Info:
                // The act of invalidating the seed property of a reverse-inherited property
                // on the first side of the path causes the invalidation of the
                // reverse-inherited properties on both sides.  The input system has not yet
                // invalidated the seed property on the second side, so its cached value can
                // be incorrect.
                //
                return IsMouseDirectlyOver_ComputeValue();
            }
        }
 
        private bool IsMouseDirectlyOver_ComputeValue()
        {
            return (Mouse.DirectlyOver == this);
        }
 
        /// <summary>
        ///     Asynchronously re-evaluate the reverse-inherited properties.
        /// </summary>
        internal void SynchronizeReverseInheritPropertyFlags(DependencyObject oldParent, bool isCoreParent)
        {
            if(IsKeyboardFocusWithin)
            {
                Keyboard.PrimaryDevice.ReevaluateFocusAsync(this, oldParent, isCoreParent);
            }
 
            // Reevelauate the stylus properties first to guarentee that our property change
            // notifications fire before mouse properties.
            if(IsStylusOver)
            {
                StylusLogic.CurrentStylusLogicReevaluateStylusOver(this, oldParent, isCoreParent);
            }
 
            if(IsStylusCaptureWithin)
            {
                StylusLogic.CurrentStylusLogicReevaluateCapture(this, oldParent, isCoreParent);
            }
 
            if(IsMouseOver)
            {
                Mouse.PrimaryDevice.ReevaluateMouseOver(this, oldParent, isCoreParent);
            }
 
            if(IsMouseCaptureWithin)
            {
                Mouse.PrimaryDevice.ReevaluateCapture(this, oldParent, isCoreParent);
            }
 
            if (AreAnyTouchesOver)
            {
                TouchDevice.ReevaluateDirectlyOver(this, oldParent, isCoreParent);
            }
 
            if (AreAnyTouchesCapturedWithin)
            {
                TouchDevice.ReevaluateCapturedWithin(this, oldParent, isCoreParent);
            }
        }
 
        /// <summary>
            /// BlockReverseInheritance method when overriden stops reverseInheritProperties from updating their parent level properties.
        /// </summary>
        internal virtual bool BlockReverseInheritance()
        {
            return false;
        }
 
        /// <summary>
        ///     A property indicating if the mouse is over this element or not.
        /// </summary>
        public bool IsMouseOver
        {
            get
            {
                return ReadFlag(CoreFlags.IsMouseOverCache);
            }
        }
 
        /// <summary>
        ///     A property indicating if the stylus is over this element or not.
        /// </summary>
        public bool IsStylusOver
        {
            get
            {
                return ReadFlag(CoreFlags.IsStylusOverCache);
            }
        }
 
        /// <summary>
        ///     Indicates if Keyboard Focus is anywhere
        ///     within in the subtree starting at the
        ///     current instance
        /// </summary>
        public bool IsKeyboardFocusWithin
        {
            get
            {
                return ReadFlag(CoreFlags.IsKeyboardFocusWithinCache);
            }
        }
 
        /// <summary>
        ///     A property indicating if the mouse is captured to this element or not.
        /// </summary>
        public bool IsMouseCaptured
        {
            get { return (bool) GetValue(IsMouseCapturedProperty); }
        }
 
        /// <summary>
        ///     Captures the mouse to this element.
        /// </summary>
        public bool CaptureMouse()
        {
            return Mouse.Capture(this);
        }
 
        /// <summary>
        ///     Releases the mouse capture.
        /// </summary>
        public void ReleaseMouseCapture()
        {
            Mouse.Capture(null);
        }
 
        /// <summary>
        ///     Indicates if mouse capture is anywhere within in the subtree
        ///     starting at the current instance
        /// </summary>
        public bool IsMouseCaptureWithin
        {
            get
            {
                return ReadFlag(CoreFlags.IsMouseCaptureWithinCache);
            }
        }
 
        /// <summary>
        ///     A property indicating if the stylus is over this element or not.
        /// </summary>
        public bool IsStylusDirectlyOver
        {
            get
            {
                // We do not return the cached value of reverse-inherited seed properties.
                //
                // The cached value is only used internally to detect a "change".
                //
                // More Info:
                // The act of invalidating the seed property of a reverse-inherited property
                // on the first side of the path causes the invalidation of the
                // reverse-inherited properties on both sides.  The input system has not yet
                // invalidated the seed property on the second side, so its cached value can
                // be incorrect.
                //
                return IsStylusDirectlyOver_ComputeValue();
            }
        }
 
        private bool IsStylusDirectlyOver_ComputeValue()
        {
            return (Stylus.DirectlyOver == this);
        }
 
        /// <summary>
        ///     A property indicating if the stylus is captured to this element or not.
        /// </summary>
        public bool IsStylusCaptured
        {
            get { return (bool) GetValue(IsStylusCapturedProperty); }
        }
 
        /// <summary>
        ///     Captures the stylus to this element.
        /// </summary>
        public bool CaptureStylus()
        {
            return Stylus.Capture(this);
        }
 
        /// <summary>
        ///     Releases the stylus capture.
        /// </summary>
        public void ReleaseStylusCapture()
        {
            Stylus.Capture(null);
        }
 
        /// <summary>
        ///     Indicates if stylus capture is anywhere within in the subtree
        ///     starting at the current instance
        /// </summary>
        public bool IsStylusCaptureWithin
        {
            get
            {
                return ReadFlag(CoreFlags.IsStylusCaptureWithinCache);
            }
        }
 
        /// <summary>
        ///     A property indicating if the keyboard is focused on this
        ///     element or not.
        /// </summary>
        public bool IsKeyboardFocused
        {
            get
            {
                // We do not return the cached value of reverse-inherited seed properties.
                //
                // The cached value is only used internally to detect a "change".
                //
                // More Info:
                // The act of invalidating the seed property of a reverse-inherited property
                // on the first side of the path causes the invalidation of the
                // reverse-inherited properties on both sides.  The input system has not yet
                // invalidated the seed property on the second side, so its cached value can
                // be incorrect.
                //
                return IsKeyboardFocused_ComputeValue();
            }
        }
 
        private bool IsKeyboardFocused_ComputeValue()
        {
            return (Keyboard.FocusedElement == this);
        }
 
        /// <summary>
        ///     Focuses the keyboard on this element.
        /// </summary>
        public bool Focus()
        {
            if (Keyboard.Focus(this) == this)
            {
                
                // In order to show the touch keyboard we need to prompt the WinRT InputPane API.
                // We only do this when the keyboard focus has changed as the keyboard focus dictates
                // our current input targets for the touch and physical keyboards.
                TipTsfHelper.Show(this);
 
                return true;
            }
 
            return false;
        }
 
        /// <summary>
        ///     Request to move the focus from this element to another element
        /// </summary>
        /// <param name="request">Determine how to move the focus</param>
        /// <returns> Returns true if focus is moved successfully. Returns false if there is no next element</returns>
        public virtual bool MoveFocus(TraversalRequest request)
        {
            return false;
        }
 
        /// <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 virtual DependencyObject PredictFocus(FocusNavigationDirection direction)
        {
            return null;
        }
 
        /// <summary>
        ///     GotFocus event
        /// </summary>
        public static readonly RoutedEvent GotFocusEvent = FocusManager.GotFocusEvent.AddOwner(typeof(ContentElement));
 
        /// <summary>
        ///     An event announcing that IsFocused changed to true.
        /// </summary>
        public event RoutedEventHandler GotFocus
        {
            add { AddHandler(GotFocusEvent, value); }
            remove { RemoveHandler(GotFocusEvent, value); }
        }
 
        /// <summary>
        ///     LostFocus event
        /// </summary>
        public static readonly RoutedEvent LostFocusEvent = FocusManager.LostFocusEvent.AddOwner(typeof(ContentElement));
 
        /// <summary>
        ///     An event announcing that IsFocused changed to false.
        /// </summary>
        public event RoutedEventHandler LostFocus
        {
            add { AddHandler(LostFocusEvent, value); }
            remove { RemoveHandler(LostFocusEvent, value); }
        }
 
        /// <summary>
        ///     The DependencyProperty for IsFocused.
        ///     Flags:              None
        ///     Read-Only:          true
        /// </summary>
        public static readonly DependencyProperty IsFocusedProperty =
                    UIElement.IsFocusedProperty.AddOwner(
                                typeof(ContentElement));
 
        private static void IsFocused_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ContentElement ce = ((ContentElement) d);
 
            if ((bool) e.NewValue)
            {
                ce.OnGotFocus(new RoutedEventArgs(GotFocusEvent, ce));
            }
            else
            {
                ce.OnLostFocus(new RoutedEventArgs(LostFocusEvent, ce));
            }
        }
 
        /// <summary>
        ///     This method is invoked when the IsFocused property changes to true
        /// </summary>
        /// <param name="e">RoutedEventArgs</param>
        protected virtual void OnGotFocus(RoutedEventArgs e)
        {
            RaiseEvent(e);
        }
 
        /// <summary>
        ///     This method is invoked when the IsFocused property changes to false
        /// </summary>
        /// <param name="e">RoutedEventArgs</param>
        protected virtual void OnLostFocus(RoutedEventArgs e)
        {
            RaiseEvent(e);
        }
 
        /// <summary>
        ///     Gettor for IsFocused Property
        /// </summary>
        public bool IsFocused
        {
            get { return (bool) GetValue(IsFocusedProperty); }
        }
 
        /// <summary>
        ///     The DependencyProperty for the IsEnabled property.
        /// </summary>
        public static readonly DependencyProperty IsEnabledProperty =
                    UIElement.IsEnabledProperty.AddOwner(
                                typeof(ContentElement),
                                new UIPropertyMetadata(
                                            BooleanBoxes.TrueBox, // default value
                                            new PropertyChangedCallback(OnIsEnabledChanged),
                                            new CoerceValueCallback(CoerceIsEnabled)));
 
 
        /// <summary>
        ///     A property indicating if this element is enabled or not.
        /// </summary>
        public bool IsEnabled
        {
            get { return (bool) GetValue(IsEnabledProperty); }
            set { SetValue(IsEnabledProperty, BooleanBoxes.Box(value)); }
        }
 
        /// <summary>
        ///     IsEnabledChanged event
        /// </summary>
        public event DependencyPropertyChangedEventHandler IsEnabledChanged
        {
            add { EventHandlersStoreAdd(UIElement.IsEnabledChangedKey, value); }
            remove { EventHandlersStoreRemove(UIElement.IsEnabledChangedKey, value); }
        }
 
        /// <summary>
        ///     Fetches the value that IsEnabled should be coerced to.
        /// </summary>
        /// <remarks>
        ///     This method is virtual is so that controls derived from UIElement
        ///     can combine additional requirements into the coersion logic.
        ///     <P/>
        ///     It is important for anyone overriding this property to also
        ///     call CoerceValue when any of their dependencies change.
        /// </remarks>
        protected virtual bool IsEnabledCore
        {
            get
            {
                // As of 1/25/2006, the following controls override this method:
                // Hyperlink.IsEnabledCore: CanExecute
                return true;
            }
        }
 
        private static object CoerceIsEnabled(DependencyObject d, object value)
        {
            ContentElement ce = (ContentElement) d;
 
            // We must be false if our parent is false, but we can be
            // either true or false if our parent is true.
            //
            // Another way of saying this is that we can only be true
            // if our parent is true, but we can always be false.
            if((bool) value)
            {
                // Use the "logical" parent.  This is different that UIElement, which
                // uses the visual parent.  But the "content parent" is not a complete
                // tree description (for instance, we don't track "content children"),
                // so the best we can do is use the logical tree for ContentElements.
                //
                // Note: we assume the "logical" parent of a ContentElement is either
                // a UIElement or ContentElement.  We explicitly assume that there
                // is never a raw Visual as the parent.
 
                DependencyObject parent = ce.GetUIParentCore();
 
                if(parent == null || (bool)parent.GetValue(IsEnabledProperty))
                {
                    return BooleanBoxes.Box(ce.IsEnabledCore);
                }
                else
                {
                    return BooleanBoxes.FalseBox;
                }
            }
            else
            {
                return BooleanBoxes.FalseBox;
            }
        }
 
        private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ContentElement ce = (ContentElement)d;
 
            // Raise the public changed event.
            ce.RaiseDependencyPropertyChanged(UIElement.IsEnabledChangedKey, e);
 
            // Invalidate the children so that they will inherit the new value.
            ce.InvalidateForceInheritPropertyOnChildren(e.Property);
 
            // The input manager needs to re-hittest because something changed
            // that is involved in the hit-testing we do, so a different result
            // could be returned.
            InputManager.SafeCurrentNotifyHitTestInvalidated();
        }
 
        //*********************************************************************
        #region Focusable Property
        //*********************************************************************
 
        /// <summary>
        ///     The DependencyProperty for the Focusable property.
        /// </summary>
        [CommonDependencyProperty]
        public static readonly DependencyProperty FocusableProperty =
                UIElement.FocusableProperty.AddOwner(
                        typeof(ContentElement),
                        new UIPropertyMetadata(
                                BooleanBoxes.FalseBox, // default value
                                new PropertyChangedCallback(OnFocusableChanged)));
 
        /// <summary>
        ///     Gettor and Settor for Focusable Property
        /// </summary>
        public bool Focusable
        {
            get { return (bool) GetValue(FocusableProperty); }
            set { SetValue(FocusableProperty, BooleanBoxes.Box(value)); }
        }
 
        /// <summary>
        ///     FocusableChanged event
        /// </summary>
        public event DependencyPropertyChangedEventHandler FocusableChanged
        {
            add {EventHandlersStoreAdd(UIElement.FocusableChangedKey, value);}
            remove {EventHandlersStoreRemove(UIElement.FocusableChangedKey, value);}
        }
 
        private static void OnFocusableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ContentElement ce = (ContentElement) d;
 
            // Raise the public changed event.
            ce.RaiseDependencyPropertyChanged(UIElement.FocusableChangedKey, e);
        }
 
        //*********************************************************************
        #endregion Focusable Property
        //*********************************************************************
 
        /// <summary>
        ///     A property indicating if the inptu method is enabled.
        /// </summary>
        public bool IsInputMethodEnabled
        {
            get { return (bool) GetValue(InputMethod.IsInputMethodEnabledProperty); }
        }
 
 
        #endregion Input
 
        #region Operations
 
        private void RaiseMouseButtonEvent(EventPrivateKey key, MouseButtonEventArgs e)
        {
            EventHandlersStore store = EventHandlersStore;
            if (store != null)
            {
                Delegate handler = store.Get(key);
                if (handler != null)
                {
                    ((MouseButtonEventHandler)handler)(this, e);
                }
            }
        }
 
        // 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);
                }
            }
        }
 
        #endregion Operations
 
        #region AllowDrop
 
        /// <summary>
        ///     The DependencyProperty for the AllowDrop property.
        /// </summary>
        public static readonly DependencyProperty AllowDropProperty =
                    UIElement.AllowDropProperty.AddOwner(
                                typeof(ContentElement),
                                new PropertyMetadata(BooleanBoxes.FalseBox));
 
        /// <summary>
        ///     A dependency property that allows the drop object as DragDrop target.
        /// </summary>
        public bool AllowDrop
        {
            get { return (bool) GetValue(AllowDropProperty); }
            set { SetValue(AllowDropProperty, BooleanBoxes.Box(value)); }
        }
 
        #endregion AllowDrop
 
        #region ForceInherit property support
 
        // 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 virtual void InvalidateForceInheritPropertyOnChildren(DependencyProperty property)
        {
        }
 
        #endregion
 
        #region Touch
 
        /// <summary>
        ///     A property indicating if any touch devices are over this element or not.
        /// </summary>
        public bool AreAnyTouchesOver
        {
            get { return ReadFlag(CoreFlags.TouchesOverCache); }
        }
 
        /// <summary>
        ///     A property indicating if any touch devices are directly over this element or not.
        /// </summary>
        public bool AreAnyTouchesDirectlyOver
        {
            get { return (bool)GetValue(AreAnyTouchesDirectlyOverProperty); }
        }
 
        /// <summary>
        ///     A property indicating if any touch devices are captured to elements in this subtree.
        /// </summary>
        public bool AreAnyTouchesCapturedWithin
        {
            get { return ReadFlag(CoreFlags.TouchesCapturedWithinCache); }
        }
 
        /// <summary>
        ///     A property indicating if any touch devices are captured to this element.
        /// </summary>
        public bool AreAnyTouchesCaptured
        {
            get { return (bool)GetValue(AreAnyTouchesCapturedProperty); }
        }
 
        /// <summary>
        ///     Captures the specified device to this element.
        /// </summary>
        /// <param name="touchDevice">The touch device to capture.</param>
        /// <returns>True if capture was taken.</returns>
        public bool CaptureTouch(TouchDevice touchDevice)
        {
            ArgumentNullException.ThrowIfNull(touchDevice);
 
            return touchDevice.Capture(this);
        }
 
        /// <summary>
        ///     Releases capture from the specified touch device.
        /// </summary>
        /// <param name="touchDevice">The device that is captured to this element.</param>
        /// <returns>true if capture was released, false otherwise.</returns>
        public bool ReleaseTouchCapture(TouchDevice touchDevice)
        {
            ArgumentNullException.ThrowIfNull(touchDevice);
 
            if (touchDevice.Captured == this)
            {
                touchDevice.Capture(null);
                return true;
            }
            else
            {
                return false;
            }
        }
 
        /// <summary>
        ///     Releases capture on any touch devices captured to this element.
        /// </summary>
        public void ReleaseAllTouchCaptures()
        {
            TouchDevice.ReleaseAllCaptures(this);
        }
 
        /// <summary>
        ///     The touch devices captured to this element.
        /// </summary>
        public IEnumerable<TouchDevice> TouchesCaptured
        {
            get
            {
                return TouchDevice.GetCapturedTouches(this, /* includeWithin = */ false);
            }
        }
 
        /// <summary>
        ///     The touch devices captured to this element and any elements in the subtree.
        /// </summary>
        public IEnumerable<TouchDevice> TouchesCapturedWithin
        {
            get
            {
                return TouchDevice.GetCapturedTouches(this, /* includeWithin = */ true);
            }
        }
 
        /// <summary>
        ///     The touch devices which are over this element and any elements in the subtree.
        ///     This is particularly relevant to elements which dont take capture (like Label).
        /// </summary>
        public IEnumerable<TouchDevice> TouchesOver
        {
            get
            {
                return TouchDevice.GetTouchesOver(this, /* includeWithin = */ true);
            }
        }
 
        /// <summary>
        ///     The touch devices which are directly over this element.
        ///     This is particularly relevant to elements which dont take capture (like Label).
        /// </summary>
        public IEnumerable<TouchDevice> TouchesDirectlyOver
        {
            get
            {
                return TouchDevice.GetTouchesOver(this, /* includeWithin = */ false);
            }
        }
 
        #endregion
 
        internal bool HasAutomationPeer
        {
            get { return ReadFlag(CoreFlags.HasAutomationPeer); }
            set { WriteFlag(CoreFlags.HasAutomationPeer, value); }
        }
 
        #region Data
 
        internal DependencyObject _parent;
 
        ///// ATTACHED STORAGE /////
        internal static readonly UncommonField<EventHandlersStore> EventHandlersStoreField = UIElement.EventHandlersStoreField;
        internal static readonly UncommonField<InputBindingCollection> InputBindingCollectionField = UIElement.InputBindingCollectionField;
        internal static readonly UncommonField<CommandBindingCollection> CommandBindingCollectionField = UIElement.CommandBindingCollectionField;
        private static readonly UncommonField<AutomationPeer> AutomationPeerField = new UncommonField<AutomationPeer>();
 
        // Caches the ContentElement's DependencyObjectType
        private static DependencyObjectType ContentElementType = DependencyObjectType.FromSystemTypeInternal(typeof(ContentElement));
      
        #endregion Data
    }
}