Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / System / Windows / UIElement.cs / 9 / UIElement.cs
//------------------------------------------------------------------------------ // //// Copyright (C) Microsoft Corporation. All rights reserved. // // //----------------------------------------------------------------------------- using MS.Utility; using MS.Internal; using MS.Internal.Media; using MS.Internal.PresentationCore; using MS.Internal.KnownBoxes; using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.ComponentModel; using System.Security; using System.Security.Permissions; using System.Windows.Automation.Peers; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Media3D; using System.Windows.Media.Animation; using System.Windows.Media.Composition; using System.Windows.Media.Effects; using System.Windows.Markup; using System.Windows.Threading; using System.Windows.Input.StylusPlugIns; namespace System.Windows { ////// Visibility - Enum which describes 3 possible visibility options. /// ///public enum Visibility : byte { /// /// Normally visible. /// Visible = 0, ////// Occupies space in the layout, but is not visible (completely transparent). /// Hidden, ////// Not visible and does not occupy any space in layout, as if it doesn't exist. /// Collapsed } ////// UIElement is the base class for frameworks building on the Windows Presentation Core. /// ////// UIElement adds to the base visual class "LIFE" - Layout, Input, Focus, and Eventing. /// UIElement can be considered roughly equivalent to an HWND in Win32, or an Element in Trident. /// UIElements can render (because they derive from Visual), visually size and position their children, /// respond to user input (including control of where input is getting sent to), /// and raise events that traverse the physical tree. public partial class UIElement : Visual, IInputElement, IAnimatable { ////// /// UIElement is the most functional type in the Windows Presentation Core. /// /// Critical: This code is used to register various thunks that are used to send input to the tree /// TreatAsSafe: This code attaches handlers that are inside the class and private. Not configurable or overridable /// [SecurityCritical,SecurityTreatAsSafe] static UIElement() { RegisterEvents(); RenderOptions.EdgeModeProperty.OverrideMetadata( typeof(UIElement), new UIPropertyMetadata(new PropertyChangedCallback(EdgeMode_Changed))); RenderOptions.BitmapScalingModeProperty.OverrideMetadata( typeof(UIElement), new UIPropertyMetadata(new PropertyChangedCallback(BitmapScalingMode_Changed))); } ////// Constructor. This form of constructor will encounter a slight perf hit since it needs to initialize Dispatcher for the instance. /// public UIElement() { Initialize(); } private void Initialize() { BeginPropertyInitialization(); NeverMeasured = true; NeverArranged = true; SnapsToDevicePixelsCache = (bool) SnapsToDevicePixelsProperty.GetDefaultValue(DependencyObjectType); ClipToBoundsCache = (bool) ClipToBoundsProperty.GetDefaultValue(DependencyObjectType); VisibilityCache = (Visibility) VisibilityProperty.GetDefaultValue(DependencyObjectType); SetFlags(true, VisualFlags.IsUIElement); // Note: IsVisibleCache is false by default. } #region AllowDrop ////// The DependencyProperty for the AllowDrop property. /// public static readonly DependencyProperty AllowDropProperty = DependencyProperty.Register( "AllowDrop", typeof(bool), typeof(UIElement), new PropertyMetadata(BooleanBoxes.FalseBox)); ////// A dependency property that allows the drop object as DragDrop target. /// public bool AllowDrop { get { return (bool) GetValue(AllowDropProperty); } set { SetValue(AllowDropProperty, BooleanBoxes.Box(value)); } } #endregion AllowDrop ////// Get the StylusPlugInCollection associated with the UIElement /// protected StylusPlugInCollection StylusPlugIns { get { StylusPlugInCollection stylusCollection = StylusPlugInsField.GetValue(this); if (stylusCollection == null) { stylusCollection = new StylusPlugInCollection(this); StylusPlugInsField.SetValue(this, stylusCollection); } return stylusCollection; } } ////// Returns the size the element computed during the Measure pass. /// This is only valid if IsMeasureValid is true. /// public Size DesiredSize { get { if(this.Visibility == Visibility.Collapsed) return new Size(0,0); else return _desiredSize; } } internal Size PreviousConstraint { get { return _previousAvailableSize; } } // This is needed to prevent dirty elements from drawing and crashing while doing so. private bool IsRenderable() { //elements that were created but never invalidated/measured are clean //from layout perspective, but we still don't want to render them //because they don't have state build up enough for that. if(NeverMeasured || NeverArranged) return false; //if element is collapsed, no rendering is needed //it is not only perf optimization, but also protection from //UIElement to break itself since RenderSize is reported as (0,0) //when UIElement is Collapsed if(ReadFlag(CoreFlags.IsCollapsed)) return false; return IsMeasureValid && IsArrangeValid; } internal void InvalidateMeasureInternal() { MeasureDirty = true; } internal void InvalidateArrangeInternal() { ArrangeDirty = true; } ////// Determines if the DesiredSize is valid. /// ////// A developer can force arrangement to be invalidated by calling InvalidateMeasure. /// IsArrangeValid and IsMeasureValid are related, /// in that arrangement cannot be valid without measurement first being valid. /// public bool IsMeasureValid { get { return !MeasureDirty; } } ////// Determines if the RenderSize and position of child elements is valid. /// ////// A developer can force arrangement to be invalidated by calling InvalidateArrange. /// IsArrangeValid and IsMeasureValid are related, in that arrangement cannot be valid without measurement first /// being valid. /// public bool IsArrangeValid { get { return !ArrangeDirty; } } ////// Invalidates the measurement state for the element. /// This has the effect of also invalidating the arrange state for the element. /// The element will be queued for an update layout that will occur asynchronously. /// public void InvalidateMeasure() { if( !MeasureDirty && !MeasureInProgress ) { Debug.Assert(MeasureRequest == null, "can't be clean and still have MeasureRequest"); // VerifyAccess(); if(!NeverMeasured) //only measured once elements are allowed in *update* queue { ContextLayoutManager ContextLayoutManager = ContextLayoutManager.From(Dispatcher); ContextLayoutManager.MeasureQueue.Add(this); } MeasureDirty = true; } } ////// Invalidates the arrange state for the element. /// The element will be queued for an update layout that will occur asynchronously. /// MeasureCore will not be called unless InvalidateMeasure is also called - or that something /// else caused the measure state to be invalidated. /// public void InvalidateArrange() { if( !ArrangeDirty && !ArrangeInProgress) { Debug.Assert(ArrangeRequest == null, "can't be clean and still have MeasureRequest"); // VerifyAccess(); if(!NeverArranged) { ContextLayoutManager ContextLayoutManager = ContextLayoutManager.From(Dispatcher); ContextLayoutManager.ArrangeQueue.Add(this); } ArrangeDirty = true; } } ////// Invalidates the rendering of the element. /// Causes public void InvalidateVisual() { InvalidateArrange(); RenderingInvalidated = true; } ///to be called at a later time. /// /// Notification that is called by Measure of a child when /// it ends up with different desired size for the child. /// ////// Default implementation simply calls invalidateMeasure(), assuming that layout of a /// parent should be updated after child changed its size. protected virtual void OnChildDesiredSizeChanged(UIElement child) { if(IsMeasureValid) { InvalidateMeasure(); } } ////// Finer point: this method can only be called in the scenario when the system calls Measure on a child, /// not when parent calls it since if parent calls it, it means parent has dirty layout and is recalculating already. /// /// This event fires every time Layout updates the layout of the trees associated with current Dispatcher. /// Layout update can happen as a result of some propety change, window resize or explicit user request. /// public event EventHandler LayoutUpdated { add { LayoutEventList.ListItem item = getLayoutUpdatedHandler(value); if(item == null) { //set a weak ref in LM item = ContextLayoutManager.From(Dispatcher).LayoutEvents.Add(value); addLayoutUpdatedHandler(value, item); } } remove { LayoutEventList.ListItem item = getLayoutUpdatedHandler(value); if(item != null) { removeLayoutUpdatedHandler(value); //remove a weak ref from LM ContextLayoutManager.From(Dispatcher).LayoutEvents.Remove(item); } } } private void addLayoutUpdatedHandler(EventHandler handler, LayoutEventList.ListItem item) { object cachedLayoutUpdatedItems = LayoutUpdatedListItemsField.GetValue(this); if(cachedLayoutUpdatedItems == null) { LayoutUpdatedListItemsField.SetValue(this, item); LayoutUpdatedHandlersField.SetValue(this, handler); } else { EventHandler cachedLayoutUpdatedHandler = LayoutUpdatedHandlersField.GetValue(this); if(cachedLayoutUpdatedHandler != null) { //second unique handler is coming in. //allocate a datastructure Hashtable list = new Hashtable(2); //add previously cached handler list.Add(cachedLayoutUpdatedHandler, cachedLayoutUpdatedItems); //add new handler list.Add(handler, item); LayoutUpdatedHandlersField.ClearValue(this); LayoutUpdatedListItemsField.SetValue(this,list); } else //already have a list { Hashtable list = (Hashtable)cachedLayoutUpdatedItems; list.Add(handler, item); } } } private LayoutEventList.ListItem getLayoutUpdatedHandler(EventHandler d) { object cachedLayoutUpdatedItems = LayoutUpdatedListItemsField.GetValue(this); if(cachedLayoutUpdatedItems == null) { return null; } else { EventHandler cachedLayoutUpdatedHandler = LayoutUpdatedHandlersField.GetValue(this); if(cachedLayoutUpdatedHandler != null) { if(cachedLayoutUpdatedHandler == d) return (LayoutEventList.ListItem)cachedLayoutUpdatedItems; } else //already have a list { Hashtable list = (Hashtable)cachedLayoutUpdatedItems; LayoutEventList.ListItem item = (LayoutEventList.ListItem)(list[d]); return item; } return null; } } private void removeLayoutUpdatedHandler(EventHandler d) { object cachedLayoutUpdatedItems = LayoutUpdatedListItemsField.GetValue(this); EventHandler cachedLayoutUpdatedHandler = LayoutUpdatedHandlersField.GetValue(this); if(cachedLayoutUpdatedHandler != null) //single handler { if(cachedLayoutUpdatedHandler == d) { LayoutUpdatedListItemsField.ClearValue(this); LayoutUpdatedHandlersField.ClearValue(this); } } else //there is an ArrayList allocated { Hashtable list = (Hashtable)cachedLayoutUpdatedItems; list.Remove(d); } } ////// Recursively propagates IsLayoutSuspended flag down to the whole v's sub tree. /// internal static void PropagateSuspendLayout(Visual v) { if(v.CheckFlagsAnd(VisualFlags.IsLayoutIslandRoot)) return; //the subtree is already suspended - happens when already suspended tree is further disassembled //no need to walk down in this case if(v.CheckFlagsAnd(VisualFlags.IsLayoutSuspended)) return; // (bug # 1623922) assert that a UIElement has not being // removed from the visual tree while updating layout. if ( Invariant.Strict && v.CheckFlagsAnd(VisualFlags.IsUIElement) ) { UIElement e = (UIElement)v; Invariant.Assert(!e.MeasureInProgress && !e.ArrangeInProgress); } v.SetFlags(true, VisualFlags.IsLayoutSuspended); v.TreeLevel = 0; int count = v.InternalVisualChildrenCount; for (int i = 0; i < count; i++) { Visual cv = v.InternalGetVisualChild(i); if (cv != null) { PropagateSuspendLayout(cv); } } } ////// Recursively resets IsLayoutSuspended flag on all visuals of the whole v's sub tree. /// For UIElements also re-inserts the UIElement into Measure and / or Arrange update queues /// if necessary. /// internal static void PropagateResumeLayout(Visual parent, Visual v) { if(v.CheckFlagsAnd(VisualFlags.IsLayoutIslandRoot)) return; //the subtree is already active - happens when new elements are added to the active tree //elements are created layout-active so they don't need to be specifically unsuspended //no need to walk down in this case //if(!v.CheckFlagsAnd(VisualFlags.IsLayoutSuspended)) return; //that can be true only on top of recursion, if suspended v is being connected to suspended parent. bool parentIsSuspended = parent == null ? false : parent.CheckFlagsAnd(VisualFlags.IsLayoutSuspended); uint parentTreeLevel = parent == null ? 0 : parent.TreeLevel; if(parentIsSuspended) return; v.SetFlags(false, VisualFlags.IsLayoutSuspended); v.TreeLevel = parentTreeLevel + 1; if (v.CheckFlagsAnd(VisualFlags.IsUIElement)) { // re-insert UIElement into the update queues UIElement e = (UIElement)v; Invariant.Assert(!e.MeasureInProgress && !e.ArrangeInProgress); bool requireMeasureUpdate = e.MeasureDirty && !e.NeverMeasured && (e.MeasureRequest == null); bool requireArrangeUpdate = e.ArrangeDirty && !e.NeverArranged && (e.ArrangeRequest == null); ContextLayoutManager contextLayoutManager = (requireMeasureUpdate || requireArrangeUpdate) ? ContextLayoutManager.From(e.Dispatcher) : null; if (requireMeasureUpdate) { contextLayoutManager.MeasureQueue.Add(e); } if (requireArrangeUpdate) { contextLayoutManager.ArrangeQueue.Add(e); } } int count = v.InternalVisualChildrenCount; for (int i = 0; i < count; i++) { Visual cv = v.InternalGetVisualChild(i); if (cv != null) { PropagateResumeLayout(v, cv); } } } ////// Updates DesiredSize of the UIElement. Must be called by parents from theor MeasureCore, to form recursive update. /// This is first pass of layout update. /// ////// Measure is called by parents on their children. Internally, Measure calls MeasureCore override on the same object, /// giving it opportunity to compute its DesiredSize. /// Available size that parent can give to the child. May be infinity (when parent wants to /// measure to content). This is soft constraint. Child can return bigger size to indicate that it wants bigger space and hope /// that parent can throw in scrolling... public void Measure(Size availableSize) { bool etwTracingEnabled = false; long perfElementID = 0; if (EventTrace.IsEnabled(EventTrace.Flags.PerToolSupport, EventTrace.Level.verbose)) { perfElementID = PerfService.GetPerfElementID(this); etwTracingEnabled = true; EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.MEASUREGUID), EventType.StartEvent, perfElementID); } // VerifyAccess(); // Disable reentrancy during the measure pass. This is because much work is done // during measure - such as inflating templates, formatting PTS stuff, creating // fonts, etc. Generally speaking, we cannot survive reentrancy in these code // paths. using(Dispatcher.DisableProcessing()) { //enforce that Measure can not receive NaN size . if(DoubleUtil.IsNaN(availableSize.Width) || DoubleUtil.IsNaN(availableSize.Height)) throw new InvalidOperationException(SR.Get(SRID.UIElement_Layout_NaNMeasure)); bool neverMeasured = NeverMeasured; if(neverMeasured) { switchVisibilityIfNeeded(this.Visibility); //to make sure effects are set correctly - otherwise it's not used //simply because it is never pulled by anybody pushVisualEffects(); } //if Collapsed, we should not Measure, keep dirty bit but remove request if ( this.Visibility == Visibility.Collapsed || ((Visual)this).CheckFlagsAnd(VisualFlags.IsLayoutSuspended) ) { //reset measure request. if(MeasureRequest != null) ContextLayoutManager.From(Dispatcher).MeasureQueue.Remove(this); // remember though that parent tried to measure at this size // in case when later this element is called to measure incrementally // it has up-to-date information stored in _previousAvailableSize if(!DoubleUtil.AreClose(availableSize, _previousAvailableSize)) { //this will ensure that element will be actually re-measured at the new available size //later when it becomes visible. InvalidateMeasureInternal(); _previousAvailableSize = availableSize; } return; } //your basic bypass. No reason to calc the same thing. if( IsMeasureValid //element is clean && !neverMeasured //previously measured && DoubleUtil.AreClose(availableSize, _previousAvailableSize)) //and contraint matches { return; } NeverMeasured = false; Size prevSize = _desiredSize; //we always want to be arranged, ensure arrange request //doing it before OnMeasure prevents unneeded requests from children in the queue InvalidateArrange(); //_measureInProgress prevents OnChildDesiredSizeChange to cause the elements be put //into the queue. MeasureInProgress = true; Size desiredSize = new Size(0,0); ContextLayoutManager layoutManager = ContextLayoutManager.From(Dispatcher); bool gotException = true; try { layoutManager.EnterMeasure(); desiredSize = MeasureCore(availableSize); gotException = false; } finally { // reset measure in progress MeasureInProgress = false; _previousAvailableSize = availableSize; layoutManager.ExitMeasure(); if(gotException) layoutManager.SetLastExceptionElement(this); } //enforce that MeasureCore can not return PositiveInfinity size even if given Infinte availabel size. //Note: NegativeInfinity can not be returned by definition of Size structure. if(double.IsPositiveInfinity(desiredSize.Width) || double.IsPositiveInfinity(desiredSize.Height)) throw new InvalidOperationException(SR.Get(SRID.UIElement_Layout_PositiveInfinityReturned, this.GetType().FullName)); //enforce that MeasureCore can not return NaN size . if(DoubleUtil.IsNaN(desiredSize.Width) || DoubleUtil.IsNaN(desiredSize.Height)) throw new InvalidOperationException(SR.Get(SRID.UIElement_Layout_NaNReturned, this.GetType().FullName)); //reset measure dirtiness MeasureDirty = false; //reset measure request. if(MeasureRequest != null) ContextLayoutManager.From(Dispatcher).MeasureQueue.Remove(this); //cache availableSize and desired size _desiredSize = desiredSize; //notify parent if our desired size changed (watefall effect) if( !MeasureDuringArrange && !DoubleUtil.AreClose(prevSize, desiredSize)) { UIElement p; IContentHost ich; GetUIParentOrICH(out p, out ich); //only one will be returned if(p != null && !p.MeasureInProgress) //this is what differs this code from signalDesiredSizeChange() p.OnChildDesiredSizeChanged(this); else if(ich != null) ich.OnChildDesiredSizeChanged(this); } } if (etwTracingEnabled == true) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.MEASUREGUID), EventType.EndEvent, perfElementID); } } //only one will be returned, whichever found first internal void GetUIParentOrICH(out UIElement uiParent, out IContentHost ich) { ich = null; uiParent = null; for(Visual v = VisualTreeHelper.GetParent(this) as Visual; v != null; v = VisualTreeHelper.GetParent(v) as Visual) { ich = v as IContentHost; if (ich != null) break; if(v.CheckFlagsAnd(VisualFlags.IsUIElement)) { uiParent = (UIElement)v; break; } } } //walks visual tree up to find UIElement parent within Element Layout Island, so stops the walk if the island's root is found internal UIElement GetUIParentWithinLayoutIsland() { UIElement uiParent = null; for(Visual v = VisualTreeHelper.GetParent(this) as Visual; v != null; v = VisualTreeHelper.GetParent(v) as Visual) { if (v.CheckFlagsAnd(VisualFlags.IsLayoutIslandRoot)) { break; } if(v.CheckFlagsAnd(VisualFlags.IsUIElement)) { uiParent = (UIElement)v; break; } } return uiParent; } ////// This method will return immediately if child is not Dirty, previously measured /// and availableSize is the same as cached. /// This method also resets the IsMeasureinvalid bit on the child. /// In case when "unbounded measure to content" is needed, parent can use availableSize /// as double.PositiveInfinity. Any returned size is OK in this case. /// /// Parents or system call this method to arrange the internals of children on a second pass of layout update. /// ////// This method internally calls ArrangeCore override, giving the derived class opportunity /// to arrange its children and/or content using final computed size. /// In their ArrangeCore overrides, derived class is supposed to create its visual structure and /// prepare itself for rendering. Arrange is called by parents /// from their implementation of ArrangeCore or by system when needed. /// This method sets Bounds=finalSize before calling ArrangeCore. /// /// This is the final size and location that parent or system wants this UIElement to assume. public void Arrange(Rect finalRect) { bool etwTracingEnabled = false; long perfElementID = 0; if (EventTrace.IsEnabled(EventTrace.Flags.PerToolSupport, EventTrace.Level.verbose)) { perfElementID = PerfService.GetPerfElementID(this); etwTracingEnabled = true; EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.ARRANGEGUID), EventType.StartEvent, perfElementID); } // VerifyAccess(); // Disable reentrancy during the arrange pass. This is because much work is done // during arrange - such as formatting PTS stuff, creating // fonts, etc. Generally speaking, we cannot survive reentrancy in these code // paths. using(Dispatcher.DisableProcessing()) { //enforce that Arrange can not come with Infinity size or NaN if( double.IsPositiveInfinity(finalRect.Width) || double.IsPositiveInfinity(finalRect.Height) || DoubleUtil.IsNaN(finalRect.Width) || DoubleUtil.IsNaN(finalRect.Height) ) { DependencyObject parent = GetUIParent() as UIElement; throw new InvalidOperationException( SR.Get( SRID.UIElement_Layout_InfinityArrange, (parent == null ? "" : parent.GetType().FullName), this.GetType().FullName)); } //if Collapsed, we should not Arrange, keep dirty bit but remove request if ( this.Visibility == Visibility.Collapsed || ((Visual)this).CheckFlagsAnd(VisualFlags.IsLayoutSuspended) ) { //reset arrange request. if(ArrangeRequest != null) ContextLayoutManager.From(Dispatcher).ArrangeQueue.Remove(this); // remember though that parent tried to arrange at this rect // in case when later this element is called to arrange incrementally // it has up-to-date information stored in _finalRect _finalRect = finalRect; return; } //in case parent did not call Measure on a child, we call it now. //parent can skip calling Measure on a child if it does not care about child's size //passing finalSize practically means "set size" because that's what Measure(sz)/Arrange(same_sz) means //Note that in case of IsLayoutSuspended (temporarily out of the tree) the MeasureDirty can be true //while it does not indicate that we should re-measure - we just came of Measure that did nothing //because of suspension if( MeasureDirty || NeverMeasured) { try { MeasureDuringArrange = true; //If never measured - that means "set size", arrange-only scenario //Otherwise - the parent previosuly measured the element at constriant //and the fact that we are arranging the measure-dirty element now means //we are not in the UpdateLayout loop but rather in manual sequence of Measure/Arrange //(like in HwndSource when new RootVisual is attached) so there are no loops and there could be //measure-dirty elements left after previosu single Measure pass) - so need to use cached constraint if(NeverMeasured) Measure(finalRect.Size); else Measure(_previousAvailableSize); } finally { MeasureDuringArrange = false; } } //bypass - if clean and rect is the same, no need to re-arrange if( !IsArrangeValid || NeverArranged || !DoubleUtil.AreClose(finalRect, _finalRect)) { bool firstArrange = NeverArranged; NeverArranged = false; ArrangeInProgress = true; ContextLayoutManager layoutManager = ContextLayoutManager.From(Dispatcher); Size oldSize = RenderSize; bool sizeChanged = false; bool gotException = true; try { layoutManager.EnterArrange(); //This has to update RenderSize ArrangeCore(finalRect); //to make sure Clip is tranferred to Visual ensureClip(finalRect.Size); // see if we need to call OnRenderSizeChanged on this element sizeChanged = markForSizeChangedIfNeeded(oldSize, RenderSize); gotException = false; } finally { ArrangeInProgress = false; layoutManager.ExitArrange(); if(gotException) layoutManager.SetLastExceptionElement(this); } _finalRect = finalRect; ArrangeDirty = false; //reset request. if(ArrangeRequest != null) ContextLayoutManager.From(Dispatcher).ArrangeQueue.Remove(this); if((sizeChanged || RenderingInvalidated || firstArrange) && IsRenderable()) { DrawingContext dc = RenderOpen(); try { if (etwTracingEnabled == true) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.ONRENDERGUID), EventType.StartEvent, perfElementID); } OnRender(dc); if (etwTracingEnabled == true) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.ONRENDERGUID), EventType.EndEvent, perfElementID); } } finally { dc.Close(); RenderingInvalidated = false; } updatePixelSnappingGuidelines(); } if (firstArrange) { EndPropertyInitialization(); } } } if (etwTracingEnabled == true) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.ARRANGEGUID), EventType.EndEvent, perfElementID); } } ////// OnRender is called by the base class when the rendering instructions of the UIElement are required. /// Note: the drawing instructions sent to DrawingContext are not rendered immediately on the screen /// but rather stored and later passed to the rendering engine at proper time. /// Derived classes override this method to draw the content of the UIElement. /// protected virtual void OnRender(DrawingContext drawingContext) { } private void updatePixelSnappingGuidelines() { if((!SnapsToDevicePixels) || (_drawingContent == null)) { this.VisualXSnappingGuidelines = this.VisualYSnappingGuidelines = null; } else { DoubleCollection xLines = this.VisualXSnappingGuidelines; if(xLines == null) { xLines = new DoubleCollection(); xLines.Add(0d); xLines.Add(this.RenderSize.Width); this.VisualXSnappingGuidelines = xLines; } else { // xLines[0] = 0d; - this already should be so // check to avoid potential dirtiness in renderer int lastGuideline = xLines.Count - 1; if(!DoubleUtil.AreClose(xLines[lastGuideline], this.RenderSize.Width)) xLines[lastGuideline] = this.RenderSize.Width; } DoubleCollection yLines = this.VisualYSnappingGuidelines; if(yLines == null) { yLines = new DoubleCollection(); yLines.Add(0d); yLines.Add(this.RenderSize.Height); this.VisualYSnappingGuidelines = yLines; } else { // yLines[0] = 0d; - this already should be so // check to avoid potential dirtiness in renderer int lastGuideline = yLines.Count - 1; if(!DoubleUtil.AreClose(yLines[lastGuideline], this.RenderSize.Height)) yLines[lastGuideline] = this.RenderSize.Height; } } } private bool markForSizeChangedIfNeeded(Size oldSize, Size newSize) { //already marked for SizeChanged, simply update the newSize bool widthChanged = !DoubleUtil.AreClose(oldSize.Width, newSize.Width); bool heightChanged = !DoubleUtil.AreClose(oldSize.Height, newSize.Height); SizeChangedInfo info = sizeChangedInfo; if(info != null) { info.Update(widthChanged, heightChanged); return true; } else if(widthChanged || heightChanged) { info = new SizeChangedInfo(this, oldSize, widthChanged, heightChanged); sizeChangedInfo = info; ContextLayoutManager.From(Dispatcher).AddToSizeChangedChain(info); // // This notifies Visual layer that hittest boundary potentially changed // PropagateFlags( this, VisualFlags.IsSubtreeDirtyForPrecompute | VisualFlags.NodeNeedsBitmapEffectUpdate, VisualProxyFlags.IsSubtreeDirtyForRender); return true; } //this result is used to determine if we need to call OnRender after Arrange //OnRender is called for 2 reasons - someone called InvalidateVisual - then OnRender is called //on next Arrange, or the size changed. return false; } ////// This is invoked after layout update before rendering if the element's RenderSize /// has changed as a result of layout update. /// /// Packaged parameters (, includes /// old and new sizes and which dimension actually changes. protected internal virtual void OnRenderSizeChanged(SizeChangedInfo info) {} /// /// Measurement override. Implement your size-to-content logic here. /// ////// MeasureCore is designed to be the main customizability point for size control of layout. /// Element authors should override this method, call Measure on each child element, /// and compute their desired size based upon the measurement of the children. /// The return value should be the desired size. /// Available size that parent can give to the child. May be infinity (when parent wants to /// measure to content). This is soft constraint. Child can return bigger size to indicate that it wants bigger space and hope /// that parent can throw in scrolling... ////// Note: It is required that a parent element calls Measure on each child or they won't be sized/arranged. /// Typical override follows a pattern roughly like this (pseudo-code): /// /// /// The key aspects of this snippet are: ////// ///
//////
///- You must call Measure on each child element
///- It is common to cache measurement information between the MeasureCore and ArrangeCore method calls
///- Calling base.MeasureCore is not required.
///- Calls to Measure on children are passing either the same availableSize as the parent, or a subset of the area depending /// on the type of layout the parent will perform (for example, it would be valid to remove the area /// for some border or padding).
///Desired Size of the control, given available size passed as parameter. protected virtual Size MeasureCore(Size availableSize) { //can not return availableSize here - this is too "greedy" and can cause the Infinity to be //returned. So the next "reasonable" choice is (0,0). return new Size(0,0); } ////// ArrangeCore allows for the customization of the final sizing and positioning of children. /// ////// Element authors should override this method, call Arrange on each visible child element, /// to size and position each child element by passing a rectangle reserved for the child within parent space. /// Note: It is required that a parent element calls Arrange on each child or they won't be rendered. /// Typical override follows a pattern roughly like this (pseudo-code): /// /// The final area within the parent that element should use to arrange itself and its children. protected virtual void ArrangeCore(Rect finalRect) { // Set the element size. RenderSize = finalRect.Size; //Set transform to reflect the offset of finalRect - parents that have multiple children //pass offset in the finalRect to communicate the location of this child withing the parent. Transform renderTransform = RenderTransform; if(renderTransform == Transform.Identity) renderTransform = null; Vector oldOffset = VisualOffset; if (!DoubleUtil.AreClose(oldOffset.X, finalRect.X) || !DoubleUtil.AreClose(oldOffset.Y, finalRect.Y)) { VisualOffset = new Vector(finalRect.X, finalRect.Y); } if (renderTransform != null) { //render transform + layout offset, create a collection TransformGroup t = new TransformGroup(); Point origin = RenderTransformOrigin; bool hasOrigin = (origin.X != 0d || origin.Y != 0d); if (hasOrigin) t.Children.Add(new TranslateTransform(-(finalRect.Width * origin.X), -(finalRect.Height * origin.Y))); t.Children.Add(renderTransform); if (hasOrigin) t.Children.Add(new TranslateTransform(finalRect.Width * origin.X, finalRect.Height * origin.Y)); VisualTransform = t; } else { VisualTransform = null; } } ////// ////// ///
////// This is a public read-only property that returns size of the UIElement. /// This size is typcally used to find out where ink of the element will go. /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Size RenderSize { get { if (this.Visibility == Visibility.Collapsed) return new Size(); else return _size; } set { _size = value; InvalidateHitTestBounds(); } } ////// This method returns the hit-test bounds of a UIElement to the underlying Visual layer. /// internal override Rect GetHitTestBounds() { Rect hitBounds = new Rect(_size); if (_drawingContent != null) { MediaContext mediaContext = MediaContext.From(Dispatcher); BoundsDrawingContextWalker ctx = mediaContext.AcquireBoundsDrawingContextWalker(); Rect resultRect = _drawingContent.GetContentBounds(ctx); mediaContext.ReleaseBoundsDrawingContextWalker(ctx); hitBounds.Union(resultRect); } return hitBounds; } ////// The RenderTransform dependency property. /// ///[CommonDependencyProperty] public static readonly DependencyProperty RenderTransformProperty = DependencyProperty.Register( "RenderTransform", typeof(Transform), typeof(UIElement), new PropertyMetadata( Transform.Identity, new PropertyChangedCallback(RenderTransform_Changed))); /// /// The RenderTransform property defines the transform that will be applied to UIElement during rendering of its content. /// This transform does not affect layout of the panel into which the UIElement is nested - the layout does not take this /// transform into account to determine the location and RenderSize of the UIElement. /// public Transform RenderTransform { get { return (Transform) GetValue(RenderTransformProperty); } set { SetValue(RenderTransformProperty, value); } } private static void RenderTransform_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uie = (UIElement)d; //if never measured, then nothing to do, it should be measured at some point if(!uie.NeverMeasured && !uie.NeverArranged) { // If the change is simply a subproperty change, there is no // need to Arrange. (which combines RenderTransform with all the // other transforms.) if (!e.IsASubPropertyChange) { uie.InvalidateArrange(); uie.AreTransformsClean = false; } } } ////// The RenderTransformOrigin dependency property. /// ///public static readonly DependencyProperty RenderTransformOriginProperty = DependencyProperty.Register( "RenderTransformOrigin", typeof(Point), typeof(UIElement), new PropertyMetadata( new Point(0d,0d), new PropertyChangedCallback(RenderTransformOrigin_Changed)), new ValidateValueCallback(IsRenderTransformOriginValid)); private static bool IsRenderTransformOriginValid(object value) { Point v = (Point)value; return ( (!DoubleUtil.IsNaN(v.X) && !Double.IsPositiveInfinity(v.X) && !Double.IsNegativeInfinity(v.X)) && (!DoubleUtil.IsNaN(v.Y) && !Double.IsPositiveInfinity(v.Y) && !Double.IsNegativeInfinity(v.Y))); } /// /// The RenderTransformOrigin property defines the center of the RenderTransform relative to /// bounds of the element. It is a Point and both X and Y components are between 0 and 1.0 - the /// (0,0) is the default value and specified top-left corner of the element, (0.5, 0.5) is the center of element /// and (1,1) is the bottom-right corner of element. /// public Point RenderTransformOrigin { get { return (Point)GetValue(RenderTransformOriginProperty); } set { SetValue(RenderTransformOriginProperty, value); } } private static void RenderTransformOrigin_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uie = (UIElement)d; //if never measured, then nothing to do, it should be measured at some point if(!uie.NeverMeasured && !uie.NeverArranged) { uie.InvalidateArrange(); uie.AreTransformsClean = false; } } ////// OnVisualParentChanged is called when the parent of the Visual is changed. /// /// Old parent or null if the Visual did not have a parent before. protected internal override void OnVisualParentChanged(DependencyObject oldParent) { // Synchronize ForceInherit properties if (_parent != null) { DependencyObject parent = _parent; if (!InputElement.IsUIElement(parent) && !InputElement.IsUIElement3D(parent)) { Visual parentAsVisual = parent as Visual; if (parentAsVisual != null) { // We are being plugged into a non-UIElement visual. This // means that our parent doesn't play by the same rules we // do, so we need to track changes to our ancestors in // order to bridge the gap. parentAsVisual.VisualAncestorChanged += new AncestorChangedEventHandler(OnVisualAncestorChanged_ForceInherit); // Try to find a UIElement ancestor to use for coersion. parent = InputElement.GetContainingUIElement(parentAsVisual); } else { Visual3D parentAsVisual3D = parent as Visual3D; if (parentAsVisual3D != null) { // We are being plugged into a non-UIElement visual. This // means that our parent doesn't play by the same rules we // do, so we need to track changes to our ancestors in // order to bridge the gap. parentAsVisual3D.VisualAncestorChanged += new AncestorChangedEventHandler(OnVisualAncestorChanged_ForceInherit); // Try to find a UIElement ancestor to use for coersion. parent = InputElement.GetContainingUIElement(parentAsVisual3D); } } } if (parent != null) { SynchronizeForceInheritProperties(this, null, null, parent); } else { // We don't have a UIElement parent or ancestor, so no // coersions are necessary at this time. } } else { DependencyObject parent = oldParent; if (!InputElement.IsUIElement(parent) && !InputElement.IsUIElement3D(parent)) { // We are being unplugged from a non-UIElement visual. This // means that our parent didn't play by the same rules we // do, so we started track changes to our ancestors in // order to bridge the gap. Now we can stop. if (oldParent is Visual) { ((Visual) oldParent).VisualAncestorChanged -= new AncestorChangedEventHandler(OnVisualAncestorChanged_ForceInherit); } else if (oldParent is Visual3D) { ((Visual3D) oldParent).VisualAncestorChanged -= new AncestorChangedEventHandler(OnVisualAncestorChanged_ForceInherit); } // Try to find a UIElement ancestor to use for coersion. parent = InputElement.GetContainingUIElement(oldParent); } if (parent != null) { SynchronizeForceInheritProperties(this, null, null, parent); } else { // We don't have a UIElement parent or ancestor, so no // coersions are necessary at this time. } } // Synchronize ReverseInheritProperty Flags // // NOTE: do this AFTER synchronizing force-inherited flags, since // they often effect focusability and such. this.SynchronizeReverseInheritPropertyFlags(oldParent, true); } private void OnVisualAncestorChanged_ForceInherit(object sender, AncestorChangedEventArgs e) { // NOTE: // // We are forced to listen to AncestorChanged events because // a UIElement may have raw Visuals between it and its nearest // UIElement parent. We only care about changes that happen // to the visual tree BETWEEN this UIElement and its nearest // UIElement parent. This is because we can rely on our // nearest UIElement parent to notify us when its force-inherit // properties change. DependencyObject parent = null; if(e.OldParent == null) { // We were plugged into something. // Find our nearest UIElement parent. parent = InputElement.GetContainingUIElement(_parent); // See if this parent is a child of the ancestor who's parent changed. // If so, we don't care about changes that happen above us. if(parent != null && VisualTreeHelper.IsAncestorOf(e.Ancestor, parent)) { parent = null; } } else { // we were unplugged from something. // Find our nearest UIElement parent. parent = InputElement.GetContainingUIElement(_parent); if(parent != null) { // If we found a UIElement parent in our subtree, the // break in the visual tree must have been above it, // so we don't need to respond. parent = null; } else { // There was no UIElement parent in our subtree, so we // may be detaching from some UIElement parent above // the break point in the tree. parent = InputElement.GetContainingUIElement(e.OldParent); } } if(parent != null) { SynchronizeForceInheritProperties(this, null, null, parent); } } internal void OnVisualAncestorChanged(object sender, AncestorChangedEventArgs e) { UIElement uie = sender as UIElement; if(null != uie) PresentationSource.OnVisualAncestorChanged(uie, e); } ////// 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. /// internal DependencyObject GetUIParent() { return UIElementHelper.GetUIParent(this, false); } internal DependencyObject GetUIParent(bool continuePastVisualTree) { return UIElementHelper.GetUIParent(this, continuePastVisualTree); } internal DependencyObject GetUIParentNo3DTraversal() { DependencyObject parent = null; // Try to find a UIElement parent in the visual ancestry. DependencyObject myParent = InternalVisualParent; parent = InputElement.GetContainingUIElement(myParent, true); return parent; } ////// Called to get the UI parent of this element when there is /// no visual parent. /// ////// Returns a non-null value when some framework implementation /// of this method has a non-visual parent connection, /// protected virtual internal DependencyObject GetUIParentCore() { return null; } ////// Call this method to ensure that the whoel subtree of elements that includes this UIElement /// is properly updated. /// ////// This ensures that UIElements with IsMeasureInvalid or IsArrangeInvalid will /// get call to their MeasureCore and ArrangeCore, and all computed sizes will be validated. /// This method does nothing if layout is clean but it does work if layout is not clean so avoid calling /// it after each change in the element tree. It makes sense to either never call it (system will do this /// in a deferred manner) or only call it if you absolutely need updated sizes and positions after you do all changes. /// public void UpdateLayout() { // VerifyAccess(); ContextLayoutManager.From(Dispatcher).UpdateLayout(); } internal static void BuildRouteHelper(DependencyObject e, EventRoute route, RoutedEventArgs args) { if (route == null) { throw new ArgumentNullException("route"); } if (args == null) { throw new ArgumentNullException("args"); } if (args.Source == null) { throw new ArgumentException(SR.Get(SRID.SourceNotSet)); } if (args.RoutedEvent != route.RoutedEvent) { throw new ArgumentException(SR.Get(SRID.Mismatched_RoutedEvent)); } // Route via visual tree if (args.RoutedEvent.RoutingStrategy == RoutingStrategy.Direct) { UIElement uiElement = e as UIElement; ContentElement contentElement = null; UIElement3D uiElement3D = null; if (uiElement == null) { contentElement = e as ContentElement; if (contentElement == null) { uiElement3D = e as UIElement3D; } } // Add this element to route if (uiElement != null) { uiElement.AddToEventRoute(route, args); } else if (contentElement != null) { contentElement.AddToEventRoute(route, args); } else if (uiElement3D != null) { uiElement3D.AddToEventRoute(route, args); } } else { int cElements = 0; while (e != null) { UIElement uiElement = e as UIElement; ContentElement contentElement = null; UIElement3D uiElement3D = null; if (uiElement == null) { contentElement = e as ContentElement; } if (contentElement == null) { uiElement3D = e as UIElement3D; } // Protect against infinite loops by limiting the number of elements // that we will process. if (cElements++ > MAX_ELEMENTS_IN_ROUTE) { throw new InvalidOperationException(SR.Get(SRID.TreeLoop)); } // Allow the element to adjust source object newSource = null; if (uiElement != null) { newSource = uiElement.AdjustEventSource(args); } else if (contentElement != null) { newSource = contentElement.AdjustEventSource(args); } else if (uiElement3D != null) { newSource = uiElement3D.AdjustEventSource(args); } // Add changed source information to the route if (newSource != null) { route.AddSource(newSource); } // Invoke BuildRouteCore bool continuePastVisualTree = false; if (uiElement != null) { continuePastVisualTree = uiElement.BuildRouteCore(route, args); // Add this element to route uiElement.AddToEventRoute(route, args); // Get element's visual parent e = uiElement.GetUIParent(continuePastVisualTree); } else if (contentElement != null) { continuePastVisualTree = contentElement.BuildRouteCore(route, args); // Add this element to route contentElement.AddToEventRoute(route, args); // Get element's visual parent e = (DependencyObject) contentElement.GetUIParent(continuePastVisualTree); } else if (uiElement3D != null) { continuePastVisualTree = uiElement3D.BuildRouteCore(route, args); // Add this element to route uiElement3D.AddToEventRoute(route, args); // Get element's visual parent e = uiElement3D.GetUIParent(continuePastVisualTree); } // If the BuildRouteCore implementation changed the // args.Source to the route parent, respect it in // the actual route. if (e == args.Source) { route.AddSource(e); } } } } ////// Adds a handler for the given attached event /// [FriendAccessAllowed] // Built into Core, also used by Framework. internal static void AddHandler(DependencyObject d, RoutedEvent routedEvent, Delegate handler) { if (d == null) { throw new ArgumentNullException("d"); } Debug.Assert(routedEvent != null, "RoutedEvent must not be null"); UIElement uiElement = d as UIElement; if (uiElement != null) { uiElement.AddHandler(routedEvent, handler); } else { ContentElement contentElement = d as ContentElement; if (contentElement != null) { contentElement.AddHandler(routedEvent, handler); } else { UIElement3D uiElement3D = d as UIElement3D; if (uiElement3D != null) { uiElement3D.AddHandler(routedEvent, handler); } else { throw new ArgumentException(SR.Get(SRID.Invalid_IInputElement, d.GetType())); } } } } ////// Removes a handler for the given attached event /// [FriendAccessAllowed] // Built into Core, also used by Framework. internal static void RemoveHandler(DependencyObject d, RoutedEvent routedEvent, Delegate handler) { if (d == null) { throw new ArgumentNullException("d"); } Debug.Assert(routedEvent != null, "RoutedEvent must not be null"); UIElement uiElement = d as UIElement; if (uiElement != null) { uiElement.RemoveHandler(routedEvent, handler); } else { ContentElement contentElement = d as ContentElement; if (contentElement != null) { contentElement.RemoveHandler(routedEvent, handler); } else { UIElement3D uiElement3D = d as UIElement3D; if (uiElement3D != null) { uiElement3D.RemoveHandler(routedEvent, handler); } else { throw new ArgumentException(SR.Get(SRID.Invalid_IInputElement, d.GetType())); } } } } #region LoadedAndUnloadedEvents ////// Initiate the processing for [Un]Loaded event broadcast starting at this node /// internal virtual void OnPresentationSourceChanged(bool attached) { // Reset the FocusedElementProperty in order to get LostFocus event if (!attached && FocusManager.GetFocusedElement(this)!=null) FocusManager.SetFocusedElement(this, null); } #endregion LoadedAndUnloadedEvents ////// Translates a point relative to this element to coordinates that /// are relative to the specified element. /// ////// Passing null indicates that coordinates should be relative to /// the root element in the tree that this element belongs to. /// public Point TranslatePoint(Point point, UIElement relativeTo) { return InputElement.TranslatePoint(point, this, relativeTo); } ////// Returns the input element within this element that is /// at the specified coordinates relative to this element. /// public IInputElement InputHitTest(Point point) { IInputElement enabledHit; IInputElement rawHit; InputHitTest(point, out enabledHit, out rawHit); return enabledHit; } ////// Returns the input element within this element that is /// at the specified coordinates relative to this element. /// /// /// This is the coordinate, relative to this element, at which /// to look for elements within this one. /// /// /// This element is the deepest enabled input element that is at the /// specified coordinates. /// /// /// This element is the deepest input element (not necessarily enabled) /// that is at the specified coordinates. /// internal void InputHitTest(Point pt, out IInputElement enabledHit, out IInputElement rawHit) { PointHitTestParameters hitTestParameters = new PointHitTestParameters(pt); // We store the result of the hit testing here. Note that the // HitTestResultCallback is an instance method on this class // so that it can store the element we hit. InputHitTestResult result = new InputHitTestResult(); VisualTreeHelper.HitTest(this, new HitTestFilterCallback(InputHitTestFilterCallback), new HitTestResultCallback(result.InputHitTestResultCallback), hitTestParameters); DependencyObject candidate = result.Result; rawHit = candidate as IInputElement; enabledHit = null; while (candidate != null) { IContentHost contentHost = candidate as IContentHost; if (contentHost != null) { // Do not call IContentHost.InputHitTest if the containing UIElement // is not enabled. DependencyObject containingElement = InputElement.GetContainingUIElement(candidate); if ((bool)containingElement.GetValue(IsEnabledProperty)) { pt = InputElement.TranslatePoint(pt, this, candidate); enabledHit = rawHit = contentHost.InputHitTest(pt); if (enabledHit != null) { break; } } } UIElement element = candidate as UIElement; if (element != null) { if (rawHit == null) { // Earlier we hit a non-IInputElement. This is the first one // we've found, so use that as rawHit. rawHit = element; } if (element.IsEnabled) { enabledHit = element; break; } } UIElement3D element3D = candidate as UIElement3D; if (element3D != null) { if (rawHit == null) { // Earlier we hit a non-IInputElement. This is the first one // we've found, so use that as rawHit. rawHit = element3D; } if (element3D.IsEnabled) { enabledHit = element3D; break; } } if (candidate == this) { // We are at the element where the hit-test was initiated. // If we haven't found the hit element by now, we missed // everything. break; } candidate = VisualTreeHelper.GetParentInternal(candidate); } } private HitTestFilterBehavior InputHitTestFilterCallback(DependencyObject currentNode) { HitTestFilterBehavior behavior = HitTestFilterBehavior.Continue; if(UIElementHelper.IsUIElementOrUIElement3D(currentNode)) { if(!UIElementHelper.IsVisible(currentNode)) { // The element we are currently processing is not visible, // so we do not allow hit testing to continue down this // subtree. behavior = HitTestFilterBehavior.ContinueSkipSelfAndChildren; } if(!UIElementHelper.IsHitTestVisible(currentNode)) { // The element we are currently processing is not visible for hit testing, // so we do not allow hit testing to continue down this // subtree. behavior = HitTestFilterBehavior.ContinueSkipSelfAndChildren; } } else { // This is just a raw Visual, so it cannot receive input. // We allow the hit testing to continue through this visual. // // When we report the final input, we will return the containing // UIElement. behavior = HitTestFilterBehavior.Continue; } return behavior; } private class InputHitTestResult { public HitTestResultBehavior InputHitTestResultCallback(HitTestResult result) { _result = result; return HitTestResultBehavior.Stop; } public DependencyObject Result { get { return _result != null ? _result.VisualHit : null; } } private HitTestResult _result; } // // Left/Right Mouse Button Cracking Routines: // internal static RoutedEvent CrackMouseButtonEvent(MouseButtonEventArgs e) { RoutedEvent newEvent = null; switch(e.ChangedButton) { case MouseButton.Left: if(e.RoutedEvent == Mouse.PreviewMouseDownEvent) newEvent = UIElement.PreviewMouseLeftButtonDownEvent; else if(e.RoutedEvent == Mouse.MouseDownEvent) newEvent = UIElement.MouseLeftButtonDownEvent; else if(e.RoutedEvent == Mouse.PreviewMouseUpEvent) newEvent = UIElement.PreviewMouseLeftButtonUpEvent; else newEvent = UIElement.MouseLeftButtonUpEvent; break; case MouseButton.Right: if(e.RoutedEvent == Mouse.PreviewMouseDownEvent) newEvent = UIElement.PreviewMouseRightButtonDownEvent; else if(e.RoutedEvent == Mouse.MouseDownEvent) newEvent = UIElement.MouseRightButtonDownEvent; else if(e.RoutedEvent == Mouse.PreviewMouseUpEvent) newEvent = UIElement.PreviewMouseRightButtonUpEvent; else newEvent = UIElement.MouseRightButtonUpEvent; break; default: // No wrappers exposed for the other buttons. break; } return ( newEvent ); } private void CrackMouseButtonEventAndReRaiseEvent(MouseButtonEventArgs e) { RoutedEvent newEvent = CrackMouseButtonEvent(e); if(newEvent != null) { ReRaiseEventAs(e, newEvent); } } ////// A property indicating if the mouse is over this element or not. /// 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); } #region new ////// Asynchronously re-evaluate the reverse-inherited properties. /// [FriendAccessAllowed] 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); } } ////// Controls like popup want to control updating parent properties. This method /// provides an opportunity for those controls to participate and block it. /// internal virtual bool BlockReverseInheritance() { return false; } ////// A property indicating if the mouse is over this element or not. /// public bool IsMouseOver { get { return ReadFlag(CoreFlags.IsMouseOverCache); } } ////// A property indicating if the stylus is over this element or not. /// public bool IsStylusOver { get { return ReadFlag(CoreFlags.IsStylusOverCache); } } ////// Indicates if Keyboard Focus is anywhere /// within in the subtree starting at the /// current instance /// public bool IsKeyboardFocusWithin { get { return ReadFlag(CoreFlags.IsKeyboardFocusWithinCache); } } #endregion new ////// A property indicating if the mouse is captured to this element or not. /// public bool IsMouseCaptured { get { return (bool) GetValue(IsMouseCapturedProperty); } } ////// Captures the mouse to this element. /// public bool CaptureMouse() { return Mouse.Capture(this); } ////// Releases the mouse capture. /// public void ReleaseMouseCapture() { if (Mouse.Captured == this) { Mouse.Capture(null); } } ////// Indicates if mouse capture is anywhere within the subtree /// starting at the current instance /// public bool IsMouseCaptureWithin { get { return ReadFlag(CoreFlags.IsMouseCaptureWithinCache); } } ////// A property indicating if the stylus is over this element or not. /// 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); } ////// A property indicating if the stylus is captured to this element or not. /// public bool IsStylusCaptured { get { return (bool) GetValue(IsStylusCapturedProperty); } } ////// Captures the stylus to this element. /// public bool CaptureStylus() { return Stylus.Capture(this); } ////// Releases the stylus capture. /// public void ReleaseStylusCapture() { Stylus.Capture(null); } ////// Indicates if stylus capture is anywhere within the subtree /// starting at the current instance /// public bool IsStylusCaptureWithin { get { return ReadFlag(CoreFlags.IsStylusCaptureWithinCache); } } ////// A property indicating if the keyboard is focused on this /// element or not. /// 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); } ////// Set a logical focus on the element. If the current keyboard focus is within the same scope move the keyboard on this element. /// public bool Focus() { if (Keyboard.Focus(this) == this) { // Successfully setting the keyboard focus updated the logical focus as well return true; } if (Focusable && IsEnabled) { // If we cannot set keyboard focus then set the logical focus only // Find element's FocusScope and set its FocusedElement if not already set // If FocusedElement is already set we don't want to steal focus for that scope DependencyObject focusScope = FocusManager.GetFocusScope(this); if (FocusManager.GetFocusedElement(focusScope) == null) { FocusManager.SetFocusedElement(focusScope, (IInputElement)this); } } // Return false because current KeyboardFocus is not set on the element - only the logical focus is set return false; } ////// Request to move the focus from this element to another element /// /// Determine how to move the focus ///Returns true if focus is moved successfully. Returns false if there is no next element public virtual bool MoveFocus(TraversalRequest request) { return false; } ////// Request to predict the element that should receive focus relative to this element for a /// given direction, without actually moving focus to it. /// /// The direction for which focus should be predicted ////// Returns the next element that focus should move to for a given FocusNavigationDirection. /// Returns null if focus cannot be moved relative to this element. /// public virtual DependencyObject PredictFocus(FocusNavigationDirection direction) { return null; } ////// The access key for this element was invoked. Base implementation sets focus to the element. /// /// The arguments to the access key event protected virtual void OnAccessKey(AccessKeyEventArgs e) { this.Focus(); } ////// A property indicating if the inptu method is enabled. /// public bool IsInputMethodEnabled { get { return (bool) GetValue(InputMethod.IsInputMethodEnabledProperty); } } ////// The Opacity property. /// public static readonly DependencyProperty OpacityProperty = DependencyProperty.Register( "Opacity", typeof(double), typeof(UIElement), new UIPropertyMetadata( 1.0d, new PropertyChangedCallback(Opacity_Changed))); private static void Opacity_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uie = (UIElement) d; uie.pushOpacity(); } ////// Opacity applied to the rendered content of the UIElement. When set, this opacity value /// is applied uniformly to the entire UIElement. /// [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] public double Opacity { get { return (double) GetValue(OpacityProperty); } set { SetValue(OpacityProperty, value); } } private void pushOpacity() { if(this.Visibility == Visibility.Visible) { base.VisualOpacity = Opacity; } } ////// The OpacityMask property. /// public static readonly DependencyProperty OpacityMaskProperty = DependencyProperty.Register("OpacityMask", typeof(Brush), typeof(UIElement), new UIPropertyMetadata(new PropertyChangedCallback(OpacityMask_Changed))); private static void OpacityMask_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uie = (UIElement) d; uie.pushOpacityMask(); } ////// OpacityMask applied to the rendered content of the UIElement. When set, the alpha channel /// of the Brush's rendered content is applied to the rendered content of the UIElement. /// The other channels of the Brush's rendered content (e.g., Red, Green, or Blue) are ignored. /// public Brush OpacityMask { get { return (Brush) GetValue(OpacityMaskProperty); } set { SetValue(OpacityMaskProperty, value); } } private void pushOpacityMask() { base.VisualOpacityMask = OpacityMask; } ////// The BitmapEffect property. /// public static readonly DependencyProperty BitmapEffectProperty = DependencyProperty.Register( "BitmapEffect", typeof(BitmapEffect), typeof(UIElement), new UIPropertyMetadata(new PropertyChangedCallback(OnBitmapEffectChanged))); private static void OnBitmapEffectChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uie = (UIElement)d; uie.pushBitmapEffect(); } ////// BitmapEffect applied to the rendered content of the UIElement. /// public BitmapEffect BitmapEffect { get { return (BitmapEffect) GetValue(BitmapEffectProperty); } set { SetValue(BitmapEffectProperty, value); } } private void pushBitmapEffect() { base.VisualBitmapEffect = BitmapEffect; } ////// The BitmapEffectInput property. /// public static readonly DependencyProperty BitmapEffectInputProperty = DependencyProperty.Register( "BitmapEffectInput", typeof(BitmapEffectInput), typeof(UIElement), new UIPropertyMetadata(new PropertyChangedCallback(OnBitmapEffectInputChanged))); private static void OnBitmapEffectInputChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((UIElement) d).pushBitmapEffectInput((BitmapEffectInput) e.NewValue); } ////// BitmapEffectInput accessor. /// public BitmapEffectInput BitmapEffectInput { get { return (BitmapEffectInput) GetValue(BitmapEffectInputProperty); } set { SetValue(BitmapEffectInputProperty, value); } } private void pushBitmapEffectInput(BitmapEffectInput newValue) { base.VisualBitmapEffectInput = newValue; } private static void EdgeMode_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uie = (UIElement) d; uie.pushEdgeMode(); } private void pushEdgeMode() { base.VisualEdgeMode = RenderOptions.GetEdgeMode(this); } private static void BitmapScalingMode_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uie = (UIElement) d; uie.pushBitmapScalingMode(); } private void pushBitmapScalingMode() { base.VisualBitmapScalingMode = RenderOptions.GetBitmapScalingMode(this); } ////// pushVisualEffects - helper to propagate Opacity, OpacityMask, BitmapEffect, BitmapScalingMode and EdgeMode /// private void pushVisualEffects() { pushOpacity(); pushOpacityMask(); pushBitmapEffect(); pushEdgeMode(); pushBitmapScalingMode(); } ////// The Visibility property. /// [CommonDependencyProperty] public static readonly DependencyProperty VisibilityProperty = DependencyProperty.Register( "Visibility", typeof(Visibility), typeof(UIElement), new PropertyMetadata( VisibilityBoxes.VisibleBox, new PropertyChangedCallback(OnVisibilityChanged)), new ValidateValueCallback(ValidateVisibility)); private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uie = (UIElement) d; Visibility newVisibility = (Visibility) e.NewValue; uie.VisibilityCache = newVisibility; uie.switchVisibilityIfNeeded(newVisibility); // The IsVisible property depends on this property. uie.UpdateIsVisibleCache(); } private static bool ValidateVisibility(object o) { Visibility value = (Visibility) o; return (value == Visibility.Visible) || (value == Visibility.Hidden) || (value == Visibility.Collapsed); } ////// Visibility accessor /// [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] public Visibility Visibility { get { return VisibilityCache; } set { SetValue(VisibilityProperty, VisibilityBoxes.Box(value)); } } private void switchVisibilityIfNeeded(Visibility visibility) { switch(visibility) { case Visibility.Visible: ensureVisible(); break; case Visibility.Hidden: ensureInvisible(false); break; case Visibility.Collapsed: ensureInvisible(true); break; } } private void ensureVisible() { if(ReadFlag(CoreFlags.IsOpacitySuppressed)) { //restore Opacity base.VisualOpacity = Opacity; if(ReadFlag(CoreFlags.IsCollapsed)) { WriteFlag(CoreFlags.IsCollapsed, false); //invalidate parent if needed signalDesiredSizeChange(); //we are suppressing rendering (see IsRenderable) of collapsed children (to avoid //confusion when they see RenderSize=(0,0) reported for them) //so now we should invalidate to re-render if some rendering props //changed while UIElement was Collapsed (Arrange will cause re-rendering) InvalidateVisual(); } WriteFlag(CoreFlags.IsOpacitySuppressed, false); } } private void ensureInvisible(bool collapsed) { if(!ReadFlag(CoreFlags.IsOpacitySuppressed)) { base.VisualOpacity = 0; WriteFlag(CoreFlags.IsOpacitySuppressed, true); } if(!ReadFlag(CoreFlags.IsCollapsed) && collapsed) //Hidden or Visible->Collapsed { WriteFlag(CoreFlags.IsCollapsed, true); //invalidate parent signalDesiredSizeChange(); } else if(ReadFlag(CoreFlags.IsCollapsed) && !collapsed) //Collapsed -> Hidden { WriteFlag(CoreFlags.IsCollapsed, false); //invalidate parent signalDesiredSizeChange(); } } private void signalDesiredSizeChange() { UIElement p; IContentHost ich; GetUIParentOrICH(out p, out ich); //only one will be returned if(p != null) p.OnChildDesiredSizeChanged(this); else if(ich != null) ich.OnChildDesiredSizeChanged(this); } private void ensureClip(Size layoutSlotSize) { Geometry clipGeometry = GetLayoutClip(layoutSlotSize); if(Clip != null) { if(clipGeometry == null) clipGeometry = Clip; else { CombinedGeometry cg = new CombinedGeometry( GeometryCombineMode.Intersect, clipGeometry, Clip); clipGeometry = cg; } } ChangeVisualClip(clipGeometry, true /* dontSetWhenClose */); } ////// HitTestCore implements precise hit testing against render contents /// protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) { if (_drawingContent != null) { if (_drawingContent.HitTestPoint(hitTestParameters.HitPoint)) { return new PointHitTestResult(this, hitTestParameters.HitPoint); } } return null; } ////// HitTestCore implements precise hit testing against render contents /// protected override GeometryHitTestResult HitTestCore(GeometryHitTestParameters hitTestParameters) { if ((_drawingContent != null) && GetHitTestBounds().IntersectsWith(hitTestParameters.Bounds)) { IntersectionDetail intersectionDetail; intersectionDetail = _drawingContent.HitTestGeometry(hitTestParameters.InternalHitGeometry); Debug.Assert(intersectionDetail != IntersectionDetail.NotCalculated); if (intersectionDetail != IntersectionDetail.Empty) { return new GeometryHitTestResult(this, intersectionDetail); } } return null; } ////// Opens the DrawingVisual for rendering. The returned DrawingContext can be used to /// render into the DrawingVisual. /// [FriendAccessAllowed] internal DrawingContext RenderOpen() { return new VisualDrawingContext(this); } ////// Precomputes the render data content. /// internal override void PrecomputeContent() { base.PrecomputeContent(); if (_drawingContent != null) { _drawingContent.PrecomputeContent(); bool requiresRealizations = _drawingContent.ContentRequiresRealizationUpdates; // Set the NodeUsesRealizationCaches flag for this content. SetFlags(requiresRealizations, VisualFlags.NodeUsesRealizationCaches); SetFlags(_drawingContent.ContentIntroducesGraphness, VisualFlags.NodeOrDescendantIntroducesGraphness); } } ////// Called from the DrawingContext when the DrawingContext is closed. /// internal override void RenderClose(IDrawingContent newContent) { VisualFlags flags = VisualFlags.IsSubtreeDirtyForPrecompute | VisualFlags.NodeNeedsBitmapEffectUpdate; IDrawingContent oldContent = _drawingContent; //this element does not render - return if(oldContent == null && newContent == null) return; // // First cleanup the old content and the state associate with this node // related to it's content. // _drawingContent = null; if (oldContent != null) { // // Remove the notification handlers. // oldContent.PropagateChangedHandler(ContentsChangedHandler, false /* remove */); // // Disconnect the old content from this visual. // DisconnectAttachedResource( VisualProxyFlags.IsContentConnected, ((DUCE.IResource)oldContent)); } // // Prepare the new content. // if (newContent != null) { // Propagate notification handlers. newContent.PropagateChangedHandler(ContentsChangedHandler, true /* adding */); // Might need a new realization if this content contains text. SetFlags(true, VisualFlags.NodeRequiresNewRealization); flags |= VisualFlags.NodeInSubtreeRequiresNewRealization; } _drawingContent = newContent; // // Mark the visual dirty on all channels and propagate // the flags up the parent chain. // SetFlagsOnAllChannels(true, VisualProxyFlags.IsContentDirty); PropagateFlags( this, flags, VisualProxyFlags.IsSubtreeDirtyForRender); } ////// Overriding this function to release DUCE resources during Dispose and during removal of a subtree. /// ////// Critical - calls other critical code (base) /// [SecurityCritical] internal override void FreeContent(DUCE.Channel channel) { Debug.Assert(_proxy.IsOnChannel(channel)); if (_drawingContent != null) { if (CheckFlagsAnd(channel, VisualProxyFlags.IsContentConnected)) { DUCE.CompositionNode.SetContent( _proxy.GetHandle(channel), DUCE.ResourceHandle.Null, channel); ((DUCE.IResource)_drawingContent).ReleaseOnChannel(channel); SetFlags(channel, false, VisualProxyFlags.IsContentConnected); } } // Call the base method too base.FreeContent(channel); } ////// Returns the bounding box of the content. /// internal override Rect GetContentBounds() { if (_drawingContent != null) { Rect resultRect = Rect.Empty; MediaContext mediaContext = MediaContext.From(Dispatcher); BoundsDrawingContextWalker ctx = mediaContext.AcquireBoundsDrawingContextWalker(); resultRect = _drawingContent.GetContentBounds(ctx); mediaContext.ReleaseBoundsDrawingContextWalker(ctx); return resultRect; } else { return Rect.Empty; } } ////// WalkContent - method which walks the content (if present) and calls out to the /// supplied DrawingContextWalker. /// /// /// DrawingContextWalker - the target of the calls which occur during /// the content walk. /// internal void WalkContent(DrawingContextWalker walker) { VerifyAPIReadOnly(); if (_drawingContent != null) { _drawingContent.WalkContent(walker); } } ////// RenderContent is implemented by derived classes to hook up their /// content. The implementer of this function can assert that the visual /// resource is valid on a channel when the function is executed. /// internal override void RenderContent(RenderContext ctx, bool isOnChannel) { DUCE.Channel channel = ctx.Channel; Debug.Assert(!CheckFlagsAnd(channel, VisualProxyFlags.IsContentConnected)); Debug.Assert(_proxy.IsOnChannel(channel)); // // Create the content on the channel. // if (_drawingContent != null) { DUCE.IResource drawingContent = (DUCE.IResource)_drawingContent; drawingContent.AddRefOnChannel(channel); // Hookup it up to the composition node. DUCE.CompositionNode.SetContent( _proxy.GetHandle(channel), drawingContent.GetHandle(channel), channel); SetFlags( channel, true, VisualProxyFlags.IsContentConnected); } else if (isOnChannel) /* _drawingContent == null */ { DUCE.CompositionNode.SetContent( _proxy.GetHandle(channel), DUCE.ResourceHandle.Null, channel); } } ////// Called by the base class to update realization caches. /// Updates the realization cache on the content. /// internal override void UpdateRealizations(RealizationContext ctx) { if (_drawingContent != null) { _drawingContent.UpdateRealizations(ctx); } } ////// GetDrawing - Returns the drawing content of this Visual. /// ////// Changes to this DrawingGroup will not be propagated to the Visual's content. /// This method is called by both the Drawing property, and VisualTreeHelper.GetDrawing() /// internal override DrawingGroup GetDrawing() { // VerifyAPIReadOnly(); DrawingGroup drawingGroupContent = null; // Convert our content to a DrawingGroup, if content exists if (_drawingContent != null) { drawingGroupContent = DrawingServices.DrawingGroupFromRenderData((RenderData) _drawingContent); } return drawingGroupContent; } ////// This method supplies an additional (to the ///property) clip geometry /// that is used to intersect Clip in case if property is set to "true". /// Typcally, this is a size of layout space given to the UIElement. /// Geometry to use as additional clip if ClipToBounds=true protected virtual Geometry GetLayoutClip(Size layoutSlotSize) { if(ClipToBounds) { RectangleGeometry rect = new RectangleGeometry(new Rect(RenderSize)); rect.Freeze(); return rect; } else return null; } ////// ClipToBounds Property /// [CommonDependencyProperty] public static readonly DependencyProperty ClipToBoundsProperty = DependencyProperty.Register( "ClipToBounds", typeof(bool), typeof(UIElement), new PropertyMetadata( BooleanBoxes.FalseBox, // default value new PropertyChangedCallback(ClipToBounds_Changed))); private static void ClipToBounds_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uie = (UIElement) d; uie.ClipToBoundsCache = (bool) e.NewValue; //if never measured, then nothing to do, it should be measured at some point if(!uie.NeverMeasured || !uie.NeverArranged) { uie.InvalidateArrange(); } } ////// ClipToBounds Property /// ////// This property enables the content of this UIElement to be clipped by automatic Layout /// in order to "fit" into small space even if the content is larger. /// For example, if a text string is longer then available space, and Layout can not give it the /// "full" space to render, setting this property to "true" will ensure that the part of text string that /// does not fit will be automatically clipped. /// public bool ClipToBounds { get { return ClipToBoundsCache; } set { SetValue(ClipToBoundsProperty, BooleanBoxes.Box(value)); } } ////// Clip Property /// public static readonly DependencyProperty ClipProperty = DependencyProperty.Register( "Clip", typeof(Geometry), typeof(UIElement), new PropertyMetadata( (Geometry) null, new PropertyChangedCallback(Clip_Changed))); private static void Clip_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uie = (UIElement) d; // if never measured, then nothing to do, it should be measured at some point if(!uie.NeverMeasured || !uie.NeverArranged) { uie.InvalidateArrange(); } } ////// Clip Property /// public Geometry Clip { get { return (Geometry) GetValue(ClipProperty); } set { SetValue(ClipProperty, value); } } ////// Align Property /// public static readonly DependencyProperty SnapsToDevicePixelsProperty = DependencyProperty.Register( "SnapsToDevicePixels", typeof(bool), typeof(UIElement), new PropertyMetadata( BooleanBoxes.FalseBox, new PropertyChangedCallback(SnapsToDevicePixels_Changed))); private static void SnapsToDevicePixels_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uie = (UIElement) d; uie.SnapsToDevicePixelsCache = (bool) e.NewValue; // if never measured, then nothing to do, it should be measured at some point if(!uie.NeverMeasured || !uie.NeverArranged) { uie.InvalidateArrange(); } } ////// SnapsToDevicePixels Property /// public bool SnapsToDevicePixels { get { return SnapsToDevicePixelsCache; } set { SetValue(SnapsToDevicePixelsProperty, value); } } // Internal accessor for AccessKeyManager class internal void InvokeAccessKey(AccessKeyEventArgs e) { OnAccessKey(e); } ////// GotFocus event /// public static readonly RoutedEvent GotFocusEvent = FocusManager.GotFocusEvent.AddOwner(typeof(UIElement)); ////// An event announcing that IsFocused changed to true. /// public event RoutedEventHandler GotFocus { add { AddHandler(GotFocusEvent, value); } remove { RemoveHandler(GotFocusEvent, value); } } ////// LostFocus event /// public static readonly RoutedEvent LostFocusEvent = FocusManager.LostFocusEvent.AddOwner(typeof(UIElement)); ////// An event announcing that IsFocused changed to false. /// public event RoutedEventHandler LostFocus { add { AddHandler(LostFocusEvent, value); } remove { RemoveHandler(LostFocusEvent, value); } } ////// The DependencyProperty for the IsFocused property. /// internal static readonly DependencyPropertyKey IsFocusedPropertyKey = DependencyProperty.RegisterReadOnly( "IsFocused", typeof(bool), typeof(UIElement), new PropertyMetadata( BooleanBoxes.FalseBox, // default value new PropertyChangedCallback(IsFocused_Changed))); ////// The DependencyProperty for IsFocused. /// Flags: None /// Read-Only: true /// public static readonly DependencyProperty IsFocusedProperty = IsFocusedPropertyKey.DependencyProperty; private static void IsFocused_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uiElement = ((UIElement)d); if ((bool) e.NewValue) { uiElement.OnGotFocus(new RoutedEventArgs(GotFocusEvent, uiElement)); } else { uiElement.OnLostFocus(new RoutedEventArgs(LostFocusEvent, uiElement)); } } ////// This method is invoked when the IsFocused property changes to true /// /// RoutedEventArgs protected virtual void OnGotFocus(RoutedEventArgs e) { RaiseEvent(e); } ////// This method is invoked when the IsFocused property changes to false /// /// RoutedEventArgs protected virtual void OnLostFocus(RoutedEventArgs e) { RaiseEvent(e); } ////// Gettor for IsFocused Property /// public bool IsFocused { get { return (bool) GetValue(IsFocusedProperty); } } //********************************************************************* #region IsEnabled Property //********************************************************************* ////// The DependencyProperty for the IsEnabled property. /// [CommonDependencyProperty] public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register( "IsEnabled", typeof(bool), typeof(UIElement), new UIPropertyMetadata( BooleanBoxes.TrueBox, // default value new PropertyChangedCallback(OnIsEnabledChanged), new CoerceValueCallback(CoerceIsEnabled))); ////// A property indicating if this element is enabled or not. /// public bool IsEnabled { get { return (bool) GetValue(IsEnabledProperty);} set { SetValue(IsEnabledProperty, BooleanBoxes.Box(value)); } } ////// IsEnabledChanged event /// public event DependencyPropertyChangedEventHandler IsEnabledChanged { add {EventHandlersStoreAdd(IsEnabledChangedKey, value);} remove {EventHandlersStoreRemove(IsEnabledChangedKey, value);} } internal static readonly EventPrivateKey IsEnabledChangedKey = new EventPrivateKey(); // Used by ContentElement ////// Fetches the value that IsEnabled should be coerced to. /// ////// This method is virtual is so that controls derived from UIElement /// can combine additional requirements into the coersion logic. /// /// It is important for anyone overriding this property to also /// call CoerceValue when any of their dependencies change. /// protected virtual bool IsEnabledCore { get { // As of 1/25/2006, the following controls override this method: // ButtonBase.IsEnabledCore: CanExecute // MenuItem.IsEnabledCore: CanExecute // ScrollBar.IsEnabledCore: _canScroll return true; } } private static object CoerceIsEnabled(DependencyObject d, object value) { UIElement uie = (UIElement) 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) { // Our parent can constrain us. We can be plugged into either // a "visual" or "content" tree. If we are plugged into a // "content" tree, the visual tree is just considered a // visual representation, and is normally composed of raw // visuals, not UIElements, so we prefer the content tree. // // The content tree uses the "logical" links. But not all // "logical" links lead to a content tree. // DependencyObject parent = uie.GetUIParentCore() as ContentElement; if(parent == null) { parent = InputElement.GetContainingUIElement(uie._parent); } if(parent == null || (bool)parent.GetValue(IsEnabledProperty)) { return BooleanBoxes.Box(uie.IsEnabledCore); } else { return BooleanBoxes.FalseBox; } } else { return BooleanBoxes.FalseBox; } } private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uie = (UIElement)d; // Raise the public changed event. uie.RaiseDependencyPropertyChanged(IsEnabledChangedKey, e); // Invalidate the children so that they will inherit the new value. InvalidateForceInheritPropertyOnChildren(uie, 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(); //Notify Automation in case it is interested. AutomationPeer peer = uie.GetAutomationPeer(); if(peer != null) peer.InvalidatePeer(); } //********************************************************************** #endregion IsEnabled Property //********************************************************************* //********************************************************************** #region IsHitTestVisible Property //********************************************************************** ////// The DependencyProperty for the IsHitTestVisible property. /// public static readonly DependencyProperty IsHitTestVisibleProperty = DependencyProperty.Register( "IsHitTestVisible", typeof(bool), typeof(UIElement), new UIPropertyMetadata( BooleanBoxes.TrueBox, // default value new PropertyChangedCallback(OnIsHitTestVisibleChanged), new CoerceValueCallback(CoerceIsHitTestVisible))); ////// A property indicating if this element is hit test visible or not. /// public bool IsHitTestVisible { get { return (bool) GetValue(IsHitTestVisibleProperty); } set { SetValue(IsHitTestVisibleProperty, BooleanBoxes.Box(value)); } } ////// IsHitTestVisibleChanged event /// public event DependencyPropertyChangedEventHandler IsHitTestVisibleChanged { add {EventHandlersStoreAdd(IsHitTestVisibleChangedKey, value);} remove {EventHandlersStoreRemove(IsHitTestVisibleChangedKey, value);} } internal static readonly EventPrivateKey IsHitTestVisibleChangedKey = new EventPrivateKey(); // Used by ContentElement private static object CoerceIsHitTestVisible(DependencyObject d, object value) { UIElement uie = (UIElement) 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) { // Our parent can constrain us. We can be plugged into either // a "visual" or "content" tree. If we are plugged into a // "content" tree, the visual tree is just considered a // visual representation, and is normally composed of raw // visuals, not UIElements, so we prefer the content tree. // // The content tree uses the "logical" links. But not all // "logical" links lead to a content tree. // // However, ContentElements don't understand IsHitTestVisible, // so we ignore them. // DependencyObject parent = InputElement.GetContainingUIElement(uie._parent); if (parent == null || UIElementHelper.IsHitTestVisible(parent)) { return BooleanBoxes.TrueBox; } else { return BooleanBoxes.FalseBox; } } else { return BooleanBoxes.FalseBox; } } private static void OnIsHitTestVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uie = (UIElement)d; // Raise the public changed event. uie.RaiseDependencyPropertyChanged(IsHitTestVisibleChangedKey, e); // Invalidate the children so that they will inherit the new value. InvalidateForceInheritPropertyOnChildren(uie, 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(); } //********************************************************************* #endregion IsHitTestVisible Property //********************************************************************** //********************************************************************* #region IsVisible Property //********************************************************************* // The IsVisible property is a read-only reflection of the Visibility // property. private static PropertyMetadata _isVisibleMetadata = new ReadOnlyPropertyMetadata(BooleanBoxes.FalseBox, new GetReadOnlyValueCallback(GetIsVisible), new PropertyChangedCallback(OnIsVisibleChanged)); internal static readonly DependencyPropertyKey IsVisiblePropertyKey = DependencyProperty.RegisterReadOnly( "IsVisible", typeof(bool), typeof(UIElement), _isVisibleMetadata); ////// The DependencyProperty for the IsVisible property. /// public static readonly DependencyProperty IsVisibleProperty = IsVisiblePropertyKey.DependencyProperty; ////// A property indicating if this element is Visible or not. /// public bool IsVisible { get { return ReadFlag(CoreFlags.IsVisibleCache); } } private static object GetIsVisible(DependencyObject d, out BaseValueSourceInternal source) { source = BaseValueSourceInternal.Local; return ((UIElement)d).IsVisible ? BooleanBoxes.TrueBox : BooleanBoxes.FalseBox; } ////// IsVisibleChanged event /// public event DependencyPropertyChangedEventHandler IsVisibleChanged { add {EventHandlersStoreAdd(IsVisibleChangedKey, value);} remove {EventHandlersStoreRemove(IsVisibleChangedKey, value);} } internal static readonly EventPrivateKey IsVisibleChangedKey = new EventPrivateKey(); // Used by ContentElement ////// Critical - Calls a critical method (PresentationSource.CriticalFromVisual) /// TreatAsSafe - No exposure /// [SecurityCritical, SecurityTreatAsSafe] internal void UpdateIsVisibleCache() // Called from PresentationSource { // IsVisible is a read-only property. It derives its "base" value // from the Visibility property. bool isVisible = (Visibility == Visibility.Visible); // 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(isVisible) { bool constraintAllowsVisible = false; // Our parent can constrain us. We can be plugged into either // a "visual" or "content" tree. If we are plugged into a // "content" tree, the visual tree is just considered a // visual representation, and is normally composed of raw // visuals, not UIElements, so we prefer the content tree. // // The content tree uses the "logical" links. But not all // "logical" links lead to a content tree. // // However, ContentElements don't understand IsVisible, // so we ignore them. // DependencyObject parent = InputElement.GetContainingUIElement(_parent); if(parent != null) { constraintAllowsVisible = UIElementHelper.IsVisible(parent); } else { // We cannot be visible if we have no visual parent, unless: // 1) We are the root, connected to a PresentationHost. PresentationSource presentationSource = PresentationSource.CriticalFromVisual(this); if(presentationSource != null) { constraintAllowsVisible = true; } else { // CODE } } if(!constraintAllowsVisible) { isVisible = false; } } if(isVisible != IsVisible) { // Our IsVisible force-inherited property has changed. Update our // cache and raise a change notification. WriteFlag(CoreFlags.IsVisibleCache, isVisible); NotifyPropertyChange(new DependencyPropertyChangedEventArgs(IsVisibleProperty, _isVisibleMetadata, BooleanBoxes.Box(!isVisible), BooleanBoxes.Box(isVisible))); } } private static void OnIsVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uie = (UIElement) d; // Raise the public changed event. uie.RaiseDependencyPropertyChanged(IsVisibleChangedKey, e); // Invalidate the children so that they will inherit the new value. InvalidateForceInheritPropertyOnChildren(uie, 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(); } //********************************************************************* #endregion IsVisible Property //********************************************************************** //********************************************************************* #region Focusable Property //********************************************************************** ////// The DependencyProperty for the Focusable property. /// [CommonDependencyProperty] public static readonly DependencyProperty FocusableProperty = DependencyProperty.Register( "Focusable", typeof(bool), typeof(UIElement), new UIPropertyMetadata( BooleanBoxes.FalseBox, // default value new PropertyChangedCallback(OnFocusableChanged))); ////// Gettor and Settor for Focusable Property /// public bool Focusable { get { return (bool) GetValue(FocusableProperty); } set { SetValue(FocusableProperty, BooleanBoxes.Box(value)); } } ////// FocusableChanged event /// public event DependencyPropertyChangedEventHandler FocusableChanged { add {EventHandlersStoreAdd(FocusableChangedKey, value);} remove {EventHandlersStoreRemove(FocusableChangedKey, value);} } internal static readonly EventPrivateKey FocusableChangedKey = new EventPrivateKey(); // Used by ContentElement private static void OnFocusableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement uie = (UIElement) d; // Raise the public changed event. uie.RaiseDependencyPropertyChanged(FocusableChangedKey, e); } //********************************************************************** #endregion Focusable Property //********************************************************************* ////// 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 /// protected virtual AutomationPeer OnCreateAutomationPeer() { return null; } ////// 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. /// 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; } ////// 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. /// internal AutomationPeer GetAutomationPeer() { VerifyAccess(); if(HasAutomationPeer) return AutomationPeerField.GetValue(this); return null; } ////// Called by the Automation infrastructure only in the case when the UIElement does not have a specific /// peer (does not override OnCreateAutomationPeer) but we still want some generic peer to be created and cached. /// For example, this is needed when HwndTarget contains a Panel and 2 Buttons underneath - the Panel /// normally does not have a peer so only one of the Buttons is visible in the tree. /// internal AutomationPeer CreateGenericRootAutomationPeer() { VerifyAccess(); //this will ensure the AP is created in the right context AutomationPeer ap = null; // If some peer was already created, specific or generic - use it. if(HasAutomationPeer) { ap = AutomationPeerField.GetValue(this); } else { ap = new GenericRootAutomationPeer(this); AutomationPeerField.SetValue(this, ap); HasAutomationPeer = true; } return ap; } ////// This is used by the parser and journaling to uniquely identify a given element /// in a deterministic fashion, i.e., each time the same XAML/BAML is parsed/read, /// the items will be given the same PersistId. /// /// To keep PersistId from being serialized the set has been removed from the property and a separate /// set method has been created. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Obsolete("PersistId is an obsolete property and may be removed in a future release. The value of this property is not defined.")] public int PersistId { get { return _persistId; } } ////// This is used by the parser and journaling to uniquely identify a given element /// in a deterministic fashion, i.e., each time the same XAML/BAML is parsed/read, /// the items will be given the same PersistId. /// /// /// To keep PersistId from being serialized the set has been removed from the property and a separate /// set method has been created. [FriendAccessAllowed] // Built into Core, also used by Framework. internal void SetPersistId(int value) { _persistId = value; } // 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); } } } internal Rect PreviousArrangeRect { // called from PresentationFramework!System.Windows.Controls.Primitives.LayoutInformation.GetLayoutSlot() [FriendAccessAllowed] get { return _finalRect; } } // Cache for the Visibility property. Storage is in Visual._nodeProperties. private Visibility VisibilityCache { get { if (CheckFlagsAnd(VisualFlags.VisibilityCache_Visible)) { return Visibility.Visible; } else if (CheckFlagsAnd(VisualFlags.VisibilityCache_TakesSpace)) { return Visibility.Hidden; } else { return Visibility.Collapsed; } } set { Debug.Assert(value == Visibility.Visible || value == Visibility.Hidden || value == Visibility.Collapsed); switch (value) { case Visibility.Visible: SetFlags(true, VisualFlags.VisibilityCache_Visible); SetFlags(false, VisualFlags.VisibilityCache_TakesSpace); break; case Visibility.Hidden: SetFlags(false, VisualFlags.VisibilityCache_Visible); SetFlags(true, VisualFlags.VisibilityCache_TakesSpace); break; case Visibility.Collapsed: SetFlags(false, VisualFlags.VisibilityCache_Visible); SetFlags(false, VisualFlags.VisibilityCache_TakesSpace); break; } } } #region ForceInherit property support // Also called by FrameworkContentElement internal static void SynchronizeForceInheritProperties( UIElement uiElement, ContentElement contentElement, UIElement3D uiElement3D, DependencyObject parent) { if(uiElement != null || uiElement3D != null) { bool parentValue = (bool) parent.GetValue(IsEnabledProperty); if(!parentValue) { // For Read/Write force-inherited properties, use the standard coersion pattern. // // The IsEnabled property must be coerced false if the parent is false. if (uiElement != null) { uiElement.CoerceValue(IsEnabledProperty); } else { uiElement3D.CoerceValue(IsEnabledProperty); } } parentValue = (bool) parent.GetValue(IsHitTestVisibleProperty); if(!parentValue) { // For Read/Write force-inherited properties, use the standard coersion pattern. // // The IsHitTestVisible property must be coerced false if the parent is false. if (uiElement != null) { uiElement.CoerceValue(IsHitTestVisibleProperty); } else { uiElement3D.CoerceValue(IsHitTestVisibleProperty); } } parentValue = (bool) parent.GetValue(IsVisibleProperty); if(parentValue) { // For Read-Only force-inherited properties, use a private update method. // // The IsVisible property can only be true if the parent is true. if (uiElement != null) { uiElement.UpdateIsVisibleCache(); } else { uiElement3D.UpdateIsVisibleCache(); } } } else if(contentElement != null) { bool parentValue = (bool) parent.GetValue(IsEnabledProperty); if(!parentValue) { // The IsEnabled property must be coerced false if the parent is false. contentElement.CoerceValue(IsEnabledProperty); } } } // This is called from the force-inherit property changed events. internal static void InvalidateForceInheritPropertyOnChildren(Visual v, DependencyProperty property) { int cChildren = v.InternalVisual2DOr3DChildrenCount; for (int iChild = 0; iChild < cChildren; iChild++) { DependencyObject child = v.InternalGet2DOr3DVisualChild(iChild); Visual vChild = child as Visual; if (vChild != null) { UIElement element = vChild as UIElement; if (element != null) { if(property == IsVisibleProperty) { // For Read-Only force-inherited properties, use // a private update method. element.UpdateIsVisibleCache(); } else { // For Read/Write force-inherited properties, use // the standard coersion pattern. element.CoerceValue(property); } } else { // We have to "walk through" non-UIElement visuals. InvalidateForceInheritPropertyOnChildren(vChild, property); } } else { Visual3D v3DChild = child as Visual3D; if (v3DChild != null) { UIElement3D element3D = v3DChild as UIElement3D; if(element3D != null) { if(property == IsVisibleProperty) { // For Read-Only force-inherited properties, use // a private update method. element3D.UpdateIsVisibleCache(); } else { // For Read/Write force-inherited properties, use // the standard coersion pattern. element3D.CoerceValue(property); } } else { // We have to "walk through" non-UIElement visuals. UIElement3D.InvalidateForceInheritPropertyOnChildren(v3DChild, property); } } } } } #endregion ///// LAYOUT DATA ///// private Rect _finalRect; private Size _desiredSize; private Size _previousAvailableSize; private IDrawingContent _drawingContent; //right after creation all elements are Clean so go Invalidate at least one internal ContextLayoutManager.LayoutQueue.Request MeasureRequest; internal ContextLayoutManager.LayoutQueue.Request ArrangeRequest; // See PersistId property private int _persistId = 0; ///// ATTACHED STORAGE ///// // Perf analysis showed we were not using these fields enough to warrant // bloating each instance with the field, so storage is created on-demand // in the local store. internal static readonly UncommonFieldEventHandlersStoreField = new UncommonField (); internal static readonly UncommonField InputBindingCollectionField = new UncommonField (); internal static readonly UncommonField CommandBindingCollectionField = new UncommonField (); private static readonly UncommonField
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- NameValueConfigurationCollection.cs
- FontDriver.cs
- EncryptedPackageFilter.cs
- BamlMapTable.cs
- DeflateEmulationStream.cs
- InstallerTypeAttribute.cs
- AnchoredBlock.cs
- SimpleWebHandlerParser.cs
- RouteValueExpressionBuilder.cs
- TextInfo.cs
- ReflectionTypeLoadException.cs
- ParserOptions.cs
- ReflectionServiceProvider.cs
- DeclarativeCatalogPartDesigner.cs
- DeadLetterQueue.cs
- SortedDictionary.cs
- QueryStringParameter.cs
- ResourceDefaultValueAttribute.cs
- ExceptionUtil.cs
- MailMessage.cs
- ConsumerConnectionPoint.cs
- XmlSchemaSimpleContentExtension.cs
- ModelUIElement3D.cs
- SecurityContextSecurityTokenAuthenticator.cs
- WebDescriptionAttribute.cs
- RootBrowserWindowAutomationPeer.cs
- TransformerInfo.cs
- EntityType.cs
- PointAnimationUsingKeyFrames.cs
- Pkcs7Signer.cs
- OrderPreservingPipeliningMergeHelper.cs
- RayHitTestParameters.cs
- WindowsNonControl.cs
- _RequestLifetimeSetter.cs
- CommandID.cs
- InfoCardCryptoHelper.cs
- WorkflowCreationContext.cs
- TiffBitmapDecoder.cs
- FtpWebResponse.cs
- XhtmlTextWriter.cs
- Debugger.cs
- Compiler.cs
- SecurityRuntime.cs
- RadioButtonStandardAdapter.cs
- ConfigXmlCDataSection.cs
- ProcessModuleDesigner.cs
- ResourcesChangeInfo.cs
- TextElementAutomationPeer.cs
- ServerReliableChannelBinder.cs
- ChtmlSelectionListAdapter.cs
- PtsPage.cs
- ConvertersCollection.cs
- EditModeSwitchButton.cs
- NestPullup.cs
- DisplayNameAttribute.cs
- EntityContainerEmitter.cs
- ResourceManagerWrapper.cs
- XmlHierarchyData.cs
- NumericUpDownAcceleration.cs
- TabPage.cs
- _NativeSSPI.cs
- ResXBuildProvider.cs
- DataListItemEventArgs.cs
- TablePattern.cs
- SqlDataSourceSelectingEventArgs.cs
- SelectionProcessor.cs
- SqlRemoveConstantOrderBy.cs
- Grant.cs
- VectorKeyFrameCollection.cs
- TransportSecurityBindingElement.cs
- Processor.cs
- TemplatePropertyEntry.cs
- ToolstripProfessionalRenderer.cs
- OleDbReferenceCollection.cs
- MatrixIndependentAnimationStorage.cs
- ToolStripItemRenderEventArgs.cs
- DocumentReference.cs
- WindowsListViewGroupHelper.cs
- RIPEMD160Managed.cs
- SubMenuStyle.cs
- NegatedCellConstant.cs
- XNodeValidator.cs
- EventLogRecord.cs
- Emitter.cs
- CellLabel.cs
- XmlReader.cs
- FolderLevelBuildProviderCollection.cs
- DataBindingList.cs
- SamlSubjectStatement.cs
- CssTextWriter.cs
- ServerValidateEventArgs.cs
- DaylightTime.cs
- TextSelectionHighlightLayer.cs
- ControlAdapter.cs
- ResourceExpressionBuilder.cs
- SqlFacetAttribute.cs
- HeaderCollection.cs
- GenericTypeParameterBuilder.cs
- ChangeProcessor.cs
- SettingsAttributeDictionary.cs