static void AttachVisualChild_Private_MainSteps(UIElement child,
                                                        UIElement parent,
                                                        bool doesParentRequireToCreateAWrapperForEachChild,
                                                        object innerDivOfWrapperForChild,
                                                        object domElementWhereToPlaceChildStuff,
                                                        object wrapperForChild)
        {
#if REWORKLOADED
            if (INTERNAL_VisualTreeOperation.Current.Root == null)
            {
                INTERNAL_VisualTreeOperation.Current.Root = parent;
            }
#endif
            //#if CSHTML5BLAZOR && DEBUG
            //            string childIndentity = child + (child != null ? " (" + child.GetHashCode() + ")" : "");
            //            string parentIndentity = parent + (parent != null ? " (" + parent.GetHashCode() + ")" : "");
            //            Console.WriteLine("OPEN SILVER DEBUG: VisualTreeManager : AttachVisualChild_Private_FinalStepsOnlyIfControlIsVisible: " + childIndentity + " attached to " + parentIndentity);
            //#endif

            //--------------------------------------------------------
            // CREATE THE DIV FOR THE MARGINS (OPTIONAL):
            //--------------------------------------------------------

#if PERFSTAT
            var t1 = Performance.now();
#endif

            // Determine if an additional DIV for handling margins is needed:
            object additionalOutsideDivForMargins = null;
            var    margin = ((FrameworkElement)child).Margin;
            bool   containsNegativeMargins = (margin.Left < 0d || margin.Top < 0d || margin.Right < 0d || margin.Bottom < 0d);
#if ONLY_ADD_DIV_FOR_MARGINS_WHEN_MARGINS_NOT_ZERO
            bool isADivForMarginsNeeded = !(parent is Canvas) && !(child is Inline) && child is FrameworkElement;  // Note: In a Canvas, we don't want to add the additional DIV because there are no margins and we don't want to interfere with the pointer events by creating an additional DIV.
            if (isADivForMarginsNeeded)
            {
                var horizontalAlign = ((FrameworkElement)child).HorizontalAlignment;
                var verticalAlign   = ((FrameworkElement)child).VerticalAlignment;
                isADivForMarginsNeeded = !(margin.Left == 0 && margin.Top == 0 && margin.Right == 0 && margin.Bottom == 0 && horizontalAlign == HorizontalAlignment.Stretch && verticalAlign == VerticalAlignment.Stretch);
            }
#else
            bool isADivForMarginsNeeded = !(parent is Canvas) && // Note: In a Canvas, we don't want to add the additional DIV because there are no margins and we don't want to interfere with the pointer events by creating an additional DIV.
                                          !(child is Inline);      // Note: inside a TextBlock we do not want the HTML DIV because we want to create HTML SPAN elements only (otherwise there would be unwanted line returns).
#endif
            if (isADivForMarginsNeeded)
            {
                // Determine where to place it:
                object whereToPlaceDivForMargins =
                    (doesParentRequireToCreateAWrapperForEachChild
                    ? innerDivOfWrapperForChild
                    : domElementWhereToPlaceChildStuff);

                // Create and append the DIV for handling margins and append:
                additionalOutsideDivForMargins = INTERNAL_HtmlDomManager.CreateDomElementAndAppendIt("div", whereToPlaceDivForMargins, parent); //todo: check if the third parameter should be the child or the parent (make something with margins and put a mouseenter in the parent then see if the event is triggered).

                // Style the DIV for handling margins:
                var style = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(additionalOutsideDivForMargins);
                style.boxSizing = "border-box";
                if (child is FrameworkElement &&
                    (((FrameworkElement)child).HorizontalAlignment == HorizontalAlignment.Stretch && double.IsNaN(((FrameworkElement)child).Width)))
                {
                    if (!containsNegativeMargins)
                    {
                        style.width = "100%";
                    }
                }
                if (child is FrameworkElement &&
                    (((FrameworkElement)child).VerticalAlignment == VerticalAlignment.Stretch && double.IsNaN(((FrameworkElement)child).Height)))
                {
                    style.height = "100%";
                }
            }

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Create the DIV for the margin", t1);
#endif

            //--------------------------------------------------------
            // PREPARE THE CHILD:
            //--------------------------------------------------------

#if PERFSTAT
            var t2 = Performance.now();
#endif

            // Determine where to place the child:
            object whereToPlaceTheChild = (isADivForMarginsNeeded
                ? additionalOutsideDivForMargins : (doesParentRequireToCreateAWrapperForEachChild
                    ? innerDivOfWrapperForChild
                    : domElementWhereToPlaceChildStuff));

            // Set the "Parent" property of the Child (IMPORTANT: we need to do that before child.CreateDomElement because the type of the parent is used to display the child correctly):
            child.INTERNAL_VisualParent = parent;

            // Set the "ParentWindow" property so that the element knows where to display popups:
            child.INTERNAL_ParentWindow = parent.INTERNAL_ParentWindow;

            // Create and append the DOM structure of the Child:
            object domElementWhereToPlaceGrandChildren = null;
            object outerDomElement;
            bool   isChildAControl = child is Control;
            if (child.INTERNAL_HtmlRepresentation == null)
            {
                bool hasTemplate = isChildAControl && ((Control)child).HasTemplate;
                if (hasTemplate)
                {
                    outerDomElement = ((Control)child).CreateDomElementForControlTemplate(whereToPlaceTheChild, out domElementWhereToPlaceGrandChildren);
                }
                else
                {
                    outerDomElement = child.CreateDomElement(whereToPlaceTheChild, out domElementWhereToPlaceGrandChildren);
                }
            }
            else
            {
                outerDomElement = INTERNAL_HtmlDomManager.CreateDomFromStringAndAppendIt(child.INTERNAL_HtmlRepresentation, whereToPlaceTheChild, child);
            }

            // Initialize the "Width" and "Height" of the child DOM structure:
            if (child is FrameworkElement)
            {
                FrameworkElement.INTERNAL_InitializeOuterDomElementWidthAndHeight(((FrameworkElement)child), outerDomElement);
            }

            // Update the DOM structure of the Child (for example, if the child is a Grid, this will render its rows and columns):
            child.INTERNAL_UpdateDomStructureIfNecessary();

            // For debugging purposes (to better read the output html), add a class to the outer DIV that tells us the corresponding type of the element (Border, StackPanel, etc.):
            INTERNAL_HtmlDomManager.SetDomElementAttribute(outerDomElement, "class", child.GetType().ToString());

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Prepare the child", t2);
#endif

            //--------------------------------------------------------
            // REMEMBER ALL INFORMATION FOR FUTURE USE:
            //--------------------------------------------------------

#if PERFSTAT
            var t3 = Performance.now();
#endif

            // Remember the DIVs:
            child.INTERNAL_OuterDomElement = outerDomElement;
            child.INTERNAL_InnerDomElement = domElementWhereToPlaceGrandChildren;
            child.INTERNAL_AdditionalOutsideDivForMargins            = additionalOutsideDivForMargins ?? outerDomElement;
            child.INTERNAL_InnerDivOfTheChildWrapperOfTheParentIfAny = doesParentRequireToCreateAWrapperForEachChild ? innerDivOfWrapperForChild : null;

            // Remember the information about the "VisualChildren":
            if (parent.INTERNAL_VisualChildrenInformation == null)
            {
                parent.INTERNAL_VisualChildrenInformation = new Dictionary <UIElement, INTERNAL_VisualChildInformation>();
            }
            parent.INTERNAL_VisualChildrenInformation.Add(child,
                                                          new INTERNAL_VisualChildInformation()
            {
                INTERNAL_UIElement = child,
                INTERNAL_OptionalChildWrapper_OuterDomElement             = wrapperForChild,
                INTERNAL_OptionalChildWrapper_ChildWrapperInnerDomElement = innerDivOfWrapperForChild
            });

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Remember all info for future use", t3);
#endif

            //--------------------------------------------------------
            // HANDLE SPECIAL CASES:
            //--------------------------------------------------------

#if PERFSTAT
            var t4 = Performance.now();
#endif

            // If we are inside a canvas, we set the position to "absolute":
            if (parent is Canvas)
            {
                INTERNAL_HtmlDomManager.GetDomElementStyleForModification(outerDomElement).position = "absolute"; //todo: test if this works properly
            }

            UIElement.SynchronizeForceInheritProperties(child, parent);

#if REVAMPPOINTEREVENTS
            UIElement.INTERNAL_UpdateCssPointerEvents(child);
#else
            // If the current element is inside a Grid, we need to explicitly set its CSS property "PointerEvents=auto" because its parent child wrapper has "PointerEvents=none" in order to prevent its child wrappers from overlapping each other and thus preventing clicks on some children.
            if (parent is Grid && child is FrameworkElement) //todo: generalize this code so that we have no hard-reference on the Grid control, and third-party controls can use the same mechanics.
            {
                var frameworkElement = ((FrameworkElement)child);
                FrameworkElement.INTERNAL_UpdateCssPointerEventsPropertyBasedOnIsHitTestVisibleAndIsEnabled(frameworkElement, frameworkElement.IsHitTestVisible, frameworkElement.IsEnabled);
            }
#endif

            // Reset the flag that tells if we have already applied the RenderTransformOrigin (this is useful to ensure that the default RenderTransformOrigin is (0,0) like in normal XAML, instead of (0.5,0.5) like in CSS):
            child.INTERNAL_RenderTransformOriginHasBeenApplied = false;

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Handle special cases", t4);
#endif

            //--------------------------------------------------------
            // HANDLE EVENTS:
            //--------------------------------------------------------

#if PERFSTAT
            var t5 = Performance.now();
#endif

            // Register DOM events if any:
            child.INTERNAL_AttachToDomEvents();

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Handle events", t5);
#endif
            //--------------------------------------------------------
            // HANDLE INHERITED PROPERTIES:
            //--------------------------------------------------------

#if PERFSTAT
            var t6 = Performance.now();
#endif

            // Get the Inherited properties and pass them to the direct children:
            foreach (DependencyProperty dependencyProperty in
#if BRIDGE
                     INTERNAL_BridgeWorkarounds.GetDictionaryKeys_SimulatorCompatible(parent.INTERNAL_AllInheritedProperties)
#else
                     parent.INTERNAL_AllInheritedProperties.Keys
#endif
                     )
            {
                bool recursively = false; // We don't want a recursion here because the "Attach" method is already recursive due to the fact that we raise property changed on the Children property, which causes to reattach the subtree.
                INTERNAL_PropertyStorage storage = parent.INTERNAL_AllInheritedProperties[dependencyProperty];
                child.SetInheritedValue(dependencyProperty, INTERNAL_PropertyStore.GetEffectiveValue(storage), recursively);
            }

#if PERFSTAT
            Performance.Counter("Handle inherited properties", t6);
#endif

            //--------------------------------------------------------
            // SET "ISLOADED" PROPERTY AND CALL "ONATTACHED" EVENT:
            //--------------------------------------------------------

            // Tell the control that it is now present into the visual tree:
            child._isLoaded = true;

            // Raise the "OnAttached" event:
            child.INTERNAL_OnAttachedToVisualTree(); // IMPORTANT: Must be done BEFORE "RaiseChangedEventOnAllDependencyProperties" (for example, the ItemsControl uses this to initialize its visual)

            //--------------------------------------------------------
            // RENDER THE ELEMENTS BY APPLYING THE CSS PROPERTIES:
            //--------------------------------------------------------

            // Defer rendering when the control is not visible to when becomes visible (note: when this option is enabled, we do not apply the CSS properties of the UI elements that are not visible. Those property are applied later, when the control becomes visible. This option results in improved performance.)
            bool enableDeferredRenderingOfCollapsedControls =
                EnableOptimizationWhereCollapsedControlsAreNotRendered ||
                EnableOptimizationWhereCollapsedControlsAreLoadedLast ||
                EnableOptimizationWhereCollapsedControlsAreNotLoaded;

            if (enableDeferredRenderingOfCollapsedControls && !child.IsVisible)
            {
                child.INTERNAL_DeferredRenderingWhenControlBecomesVisible = () =>
                {
                    RenderElementsAndRaiseChangedEventOnAllDependencyProperties(child);
                };
            }
            else
            {
                RenderElementsAndRaiseChangedEventOnAllDependencyProperties(child);
            }

            //--------------------------------------------------------
            // HANDLE BINDING:
            //--------------------------------------------------------

#if PERFSTAT
            var t9 = Performance.now();
#endif

            child.INTERNAL_UpdateBindingsSource();

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Handle binding", t9);
#endif

            //--------------------------------------------------------
            // HANDLE TABINDEX:
            //--------------------------------------------------------

            // For GotFocus and LostFocus to work, the DIV specified by "INTERNAL_OptionalSpecifyDomElementConcernedByFocus"
            // (or the OuterDomElement otherwise) needs to have the "tabIndex" attribute set. Therefore we need to always set
            // it (unless IsTabStop is False) to its current value (default is Int32.MaxValue). At the time when this code was
            // written, there was no way to automatically call the "OnChanged" on a dependency property if no value was set.

#if !REWORKLOADED
            // IMPORTANT: This needs to be done AFTER the "OnApplyTemplate" (for example, the TextBox sets the "INTERNAL_OptionalSpecifyDomElementConcernedByFocus" in the "OnApplyTemplate").
            if (isChildAControl)
            {
                if (!(child is ContentPresenter) && !(child is TextBlock)) //ContentPresenter should not count in tabbing, as well as TextBlock (especially since TextBlock is not supposed to be a Control).
                {
                    Control.TabIndexProperty_MethodToUpdateDom(child, ((Control)child).TabIndex);
                }
            }
#endif

            //--------------------------------------------------------
            // APPLY THE VISIBILITY:
            //--------------------------------------------------------

            Visibility childVisibility = child.Visibility;
            if (childVisibility == Visibility.Collapsed)
            {
                UIElement.INTERNAL_ApplyVisibility(child, childVisibility);
            }

            //--------------------------------------------------------
            // RAISE THE "SIZECHANGED" EVENT:
            //--------------------------------------------------------
#if !REWORKLOADED
#if PERFSTAT
            var t10 = Performance.now();
#endif

            // Raise the "SizeChanged" event: (note: in XAML, the "SizeChanged" event is called before the "Loaded" event)
            // IMPORTANT: This event needs to be raised AFTER the "OnApplyTemplate" and AFTER the "IsLoaded=true" (for example, it is used in the ScrollBar implementation).
            if (child is FrameworkElement)
            {
                ((FrameworkElement)child).INTERNAL_SizeChangedWhenAttachedToVisualTree();
            }

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Raise size changed event", t10);
#endif

            //--------------------------------------------------------
            // RAISE THE "LOADED" EVENT:
            //--------------------------------------------------------
#if PERFSTAT
            var t11 = Performance.now();
#endif

            // Raise the "Loaded" event: (note: in XAML, the "loaded" event of the children is called before the "loaded" event of the parent)
            if (child is FrameworkElement)
            {
                ((FrameworkElement)child).INTERNAL_RaiseLoadedEvent();
            }

            child.StartManagingPointerPositionForPointerExitedEventIfNeeded();

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Raise Loaded event", t11);
#endif
#else
            INTERNAL_VisualTreeOperation.Current.Enqueue(child);
#endif
        }
        static void AttachVisualChild_Private_MainSteps(UIElement child,
                                                        UIElement parent,
                                                        int index,
                                                        bool doesParentRequireToCreateAWrapperForEachChild,
                                                        object innerDivOfWrapperForChild,
                                                        object domElementWhereToPlaceChildStuff,
                                                        object wrapperForChild)
        {
            //--------------------------------------------------------
            // CREATE THE DIV FOR THE MARGINS (OPTIONAL):
            //--------------------------------------------------------

#if PERFSTAT
            var t1 = Performance.now();
#endif

            // Determine if an additional DIV for handling margins is needed:
            object additionalOutsideDivForMargins = null;
            var    margin = ((FrameworkElement)child).Margin;
            bool   containsNegativeMargins = (margin.Left < 0d || margin.Top < 0d || margin.Right < 0d || margin.Bottom < 0d);
            bool   isADivForMarginsNeeded  = !(parent is Canvas) && // Note: In a Canvas, we don't want to add the additional DIV because there are no margins and we don't want to interfere with the pointer events by creating an additional DIV.
                                             !(child is Inline);   // Note: inside a TextBlock we do not want the HTML DIV because we want to create HTML SPAN elements only (otherwise there would be unwanted line returns).

            if (isADivForMarginsNeeded && (parent.IsCustomLayoutRoot || parent.IsUnderCustomLayout))
            {
                isADivForMarginsNeeded = false;
            }

            if (isADivForMarginsNeeded)
            {
                // Determine where to place it:
                object whereToPlaceDivForMargins =
                    (doesParentRequireToCreateAWrapperForEachChild
                    ? innerDivOfWrapperForChild
                    : domElementWhereToPlaceChildStuff);

                // Create and append the DIV for handling margins and append:
                additionalOutsideDivForMargins = INTERNAL_HtmlDomManager.CreateDomElementAndAppendIt("div", whereToPlaceDivForMargins, parent, index); //todo: check if the third parameter should be the child or the parent (make something with margins and put a mouseenter in the parent then see if the event is triggered).

                // Style the DIV for handling margins:
                var style = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(additionalOutsideDivForMargins);
                style.boxSizing = "border-box";
                if (child is FrameworkElement &&
                    (((FrameworkElement)child).HorizontalAlignment == HorizontalAlignment.Stretch && double.IsNaN(((FrameworkElement)child).Width)))
                {
                    if (!containsNegativeMargins)
                    {
                        style.width = "100%";
                    }
                }
                if (child is FrameworkElement &&
                    (((FrameworkElement)child).VerticalAlignment == VerticalAlignment.Stretch && double.IsNaN(((FrameworkElement)child).Height)))
                {
                    style.height = "100%";
                }
            }

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Create the DIV for the margin", t1);
#endif

            //--------------------------------------------------------
            // PREPARE THE CHILD:
            //--------------------------------------------------------

#if PERFSTAT
            var t2 = Performance.now();
#endif

            // Determine where to place the child:
            object whereToPlaceTheChild = (isADivForMarginsNeeded
                ? additionalOutsideDivForMargins : (doesParentRequireToCreateAWrapperForEachChild
                    ? innerDivOfWrapperForChild
                    : domElementWhereToPlaceChildStuff));

            child.IsConnectedToLiveTree = true;

            // Set the "ParentWindow" property so that the element knows where to display popups:
            child.INTERNAL_ParentWindow = parent.INTERNAL_ParentWindow;

            // Create and append the DOM structure of the Child:
            object domElementWhereToPlaceGrandChildren = null;
            object outerDomElement;
            bool   isChildAControl = child is Control;
            if (child.INTERNAL_HtmlRepresentation == null)
            {
                bool hasTemplate = isChildAControl && ((Control)child).HasTemplate;
                if (hasTemplate)
                {
                    outerDomElement = ((Control)child).CreateDomElementForControlTemplate(whereToPlaceTheChild, out domElementWhereToPlaceGrandChildren);
                }
                else
                {
                    outerDomElement = child.CreateDomElement(whereToPlaceTheChild, out domElementWhereToPlaceGrandChildren);
                }
            }
            else
            {
                outerDomElement = INTERNAL_HtmlDomManager.CreateDomFromStringAndAppendIt(child.INTERNAL_HtmlRepresentation, whereToPlaceTheChild, child);
            }

            // Initialize the "Width" and "Height" of the child DOM structure:
            if (child is FrameworkElement)
            {
                FrameworkElement.INTERNAL_InitializeOuterDomElementWidthAndHeight(((FrameworkElement)child), outerDomElement);
            }

            // Update the DOM structure of the Child (for example, if the child is a Grid, this will render its rows and columns):
            child.INTERNAL_UpdateDomStructureIfNecessary();

            // For debugging purposes (to better read the output html), add a class to the outer DIV that tells us the corresponding type of the element (Border, StackPanel, etc.):
            INTERNAL_HtmlDomManager.SetDomElementAttribute(outerDomElement, "class", child.GetType().ToString());

            // Set Visibility hidden when rendering with CustomLayout
            if (child.IsCustomLayoutRoot && child.Visibility == Visibility.Visible)
            {
                INTERNAL_HtmlDomManager.GetDomElementStyleForModification(outerDomElement).visibility = "hidden";
                child.isFirstRendering = true;
            }

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Prepare the child", t2);
#endif

            //--------------------------------------------------------
            // REMEMBER ALL INFORMATION FOR FUTURE USE:
            //--------------------------------------------------------

#if PERFSTAT
            var t3 = Performance.now();
#endif

            // Remember the DIVs:
            child.INTERNAL_OuterDomElement = outerDomElement;
            child.INTERNAL_InnerDomElement = domElementWhereToPlaceGrandChildren;
            child.INTERNAL_AdditionalOutsideDivForMargins            = additionalOutsideDivForMargins ?? outerDomElement;
            child.INTERNAL_InnerDivOfTheChildWrapperOfTheParentIfAny = doesParentRequireToCreateAWrapperForEachChild ? innerDivOfWrapperForChild : null;

            // Remember the information about the "VisualChildren":
            if (parent.INTERNAL_VisualChildrenInformation == null)
            {
                parent.INTERNAL_VisualChildrenInformation = new Dictionary <UIElement, INTERNAL_VisualChildInformation>();
            }
            parent.INTERNAL_VisualChildrenInformation.Add(child,
                                                          new INTERNAL_VisualChildInformation()
            {
                INTERNAL_UIElement = child,
                INTERNAL_OptionalChildWrapper_OuterDomElement             = wrapperForChild,
                INTERNAL_OptionalChildWrapper_ChildWrapperInnerDomElement = innerDivOfWrapperForChild
            });

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Remember all info for future use", t3);
#endif

            //--------------------------------------------------------
            // HANDLE SPECIAL CASES:
            //--------------------------------------------------------

#if PERFSTAT
            var t4 = Performance.now();
#endif

            // If we are inside a canvas, we set the position to "absolute":
            if (parent is Canvas)
            {
                INTERNAL_HtmlDomManager.GetDomElementStyleForModification(outerDomElement).position = "absolute"; //todo: test if this works properly
            }

            UIElement.SetPointerEvents(child);

            // Reset the flag that tells if we have already applied the RenderTransformOrigin (this is useful to ensure that the default RenderTransformOrigin is (0,0) like in normal XAML, instead of (0.5,0.5) like in CSS):
            child.INTERNAL_RenderTransformOriginHasBeenApplied = false;

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Handle special cases", t4);
#endif

            //--------------------------------------------------------
            // HANDLE EVENTS:
            //--------------------------------------------------------

#if PERFSTAT
            var t5 = Performance.now();
#endif

            // Register DOM events if any:
            child.INTERNAL_AttachToDomEvents();

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Handle events", t5);
#endif

            //--------------------------------------------------------
            // SET "ISLOADED" PROPERTY AND CALL "ONATTACHED" EVENT:
            //--------------------------------------------------------

            // Tell the control that it is now present into the visual tree:
            child._isLoaded = true;

            // Raise the "OnAttached" event:
            child.INTERNAL_OnAttachedToVisualTree(); // IMPORTANT: Must be done BEFORE "RaiseChangedEventOnAllDependencyProperties" (for example, the ItemsControl uses this to initialize its visual)

            //--------------------------------------------------------
            // RENDER THE ELEMENTS BY APPLYING THE CSS PROPERTIES:
            //--------------------------------------------------------

            // Defer rendering when the control is not visible to when becomes visible (note: when this option is enabled, we do not apply the CSS properties of the UI elements that are not visible. Those property are applied later, when the control becomes visible. This option results in improved performance.)
            bool enableDeferredRenderingOfCollapsedControls =
                EnableOptimizationWhereCollapsedControlsAreNotRendered ||
                EnableOptimizationWhereCollapsedControlsAreLoadedLast ||
                EnableOptimizationWhereCollapsedControlsAreNotLoaded;

            if (enableDeferredRenderingOfCollapsedControls && !child.IsVisible)
            {
                child.INTERNAL_DeferredRenderingWhenControlBecomesVisible = () =>
                {
                    RenderElementsAndRaiseChangedEventOnAllDependencyProperties(child);
                    child.ClearMeasureAndArrangeValidation();
                };
            }
            else
            {
                RenderElementsAndRaiseChangedEventOnAllDependencyProperties(child);
            }

            //--------------------------------------------------------
            // HANDLE BINDING:
            //--------------------------------------------------------

#if PERFSTAT
            var t9 = Performance.now();
#endif

            child.INTERNAL_UpdateBindingsSource();

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Handle binding", t9);
#endif

            //--------------------------------------------------------
            // HANDLE TABINDEX:
            //--------------------------------------------------------

            // For GotFocus and LostFocus to work, the DIV specified by "INTERNAL_OptionalSpecifyDomElementConcernedByFocus"
            // (or the OuterDomElement otherwise) needs to have the "tabIndex" attribute set. Therefore we need to always set
            // it (unless IsTabStop is False) to its current value (default is Int32.MaxValue). At the time when this code was
            // written, there was no way to automatically call the "OnChanged" on a dependency property if no value was set.

            // IMPORTANT: This needs to be done AFTER the "OnApplyTemplate" (for example, the TextBox sets the "INTERNAL_OptionalSpecifyDomElementConcernedByFocus" in the "OnApplyTemplate").
            if (isChildAControl)
            {
                if (!(child is TextBlock)) // TextBlock should not count in tabbing (TextBlock is not supposed to be a Control).
                {
                    Control.TabIndexProperty_MethodToUpdateDom(child, ((Control)child).TabIndex);
                }
            }

            //--------------------------------------------------------
            // APPLY THE VISIBILITY:
            //--------------------------------------------------------

            Visibility childVisibility = child.Visibility;
            if (childVisibility == Visibility.Collapsed)
            {
                UIElement.INTERNAL_ApplyVisibility(child, childVisibility);
            }

            //--------------------------------------------------------
            // RAISE THE "SIZECHANGED" EVENT:
            //--------------------------------------------------------
#if PERFSTAT
            var t10 = Performance.now();
#endif

            // Raise the "SizeChanged" event: (note: in XAML, the "SizeChanged" event is called before the "Loaded" event)
            // IMPORTANT: This event needs to be raised AFTER the "OnApplyTemplate" and AFTER the "IsLoaded=true" (for example, it is used in the ScrollBar implementation).
            if (child is FrameworkElement)
            {
                ((FrameworkElement)child).INTERNAL_SizeChangedWhenAttachedToVisualTree();
            }

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Raise size changed event", t10);
#endif

            //--------------------------------------------------------
            // RAISE THE "LOADED" EVENT:
            //--------------------------------------------------------
#if PERFSTAT
            var t11 = Performance.now();
#endif

            // Raise the "Loaded" event: (note: in XAML, the "loaded" event of the children is called before the "loaded" event of the parent)
            if (child is FrameworkElement)
            {
                ((FrameworkElement)child).INTERNAL_RaiseLoadedEvent();
            }

            child.StartManagingPointerPositionForPointerExitedEventIfNeeded();

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Raise Loaded event", t11);
#endif
        }
        //INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", sizeToApply.Height);

        /// <summary>
        /// Prepares the Shape so that its canvas has the size it should have, depending on its container, content and Stretch mode.
        /// </summary>
        /// <param name="frameworkElement">The Shape containing the canvas.</param>
        /// <param name="canvasDomElement">The canvas in the Shape.</param>
        /// <param name="minX">The minimum X-coordinate of the points in the Shape.</param>
        /// <param name="maxX">The maximum X-coordinate of the points in the Shape.</param>
        /// <param name="minY">The minimum Y-coordinate of the points in the Shape.</param>
        /// <param name="maxY">The maximum Y-coordinate of the points in the Shape.</param>
        /// <param name="stretch">The Stretch mode to apply on the Shape</param>
        /// <param name="shapeActualSize"></param>
        internal static void PrepareStretch(FrameworkElement frameworkElement, object canvasDomElement, double minX, double maxX, double minY, double maxY, Stretch stretch, out Size shapeActualSize)
        {
            var canvasStyle = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(canvasDomElement);

            //Two steps:
            // 1) We get the size the Shape would take if Stretch = None so that we know its prefered size
            // 2) We make the element take the allowed size closest to that prefered size.

            //We get the size the Shape would take if its Stretch mode was Stretch.None:
            //in Stretch.None mode, the size is from 0 to the rightmost poit and bottommost point:
            double sizeX = maxX;
            double sizeY = maxY;

            //in other Stretched modes, the size is from the leftmost point to the rightmost point and from the topmost to the bottommost point:
            if (stretch != Stretch.None)
            {
                sizeX = maxX - minX;
                sizeY = maxY - minY;
            }
            else //we want to add the size of the shape that goes into negative values:
            {
                if (minX < 0)
                {
                    sizeX = maxX - minX;
                }
                if (minY < 0)
                {
                    sizeY = maxY - minY;
                }
            }

            //todo: (?) for the line below, replace the "+ 1" with the StrokeThickness/LineWidth
            Size sizeToApply = new Size(Math.Max(sizeX + 1, 0), Math.Max(sizeY + 1, 0)); //example: a vertical line still needs 1 pixel width

            //we apply the possible defined size of the outerDomElement of the shape:
            dynamic style = INTERNAL_HtmlDomManager.GetFrameworkElementOuterStyleForModification(frameworkElement);
            bool    frameworkElementWidthWasSpecified = false;
            double  frameworkElementWidth             = frameworkElement.Width;
            double  frameworkElementHeight            = frameworkElement.Height;

            if (!double.IsNaN(frameworkElementWidth))
            {
                frameworkElementWidthWasSpecified = true;
                sizeToApply.Width = frameworkElementWidth + 1;
                style.width       = sizeToApply.Width + "px";
            }
            bool frameworkElementHeightWasSpecified = false;

            if (!double.IsNaN(frameworkElementHeight))
            {
                frameworkElementHeightWasSpecified = true;
                sizeToApply.Height = frameworkElementHeight + 1;
                style.height       = sizeToApply.Height + "px";
            }

            //We apply the size defined earlier (size either by the Width and/or Height of the Shape (when they are set) or by the width and/or height of its content):
            INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "width", sizeToApply.Width);
            INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", sizeToApply.Height);

            canvasStyle.width  = sizeToApply.Width + "px"; // The "sizeToApply" is the size that the shape would take if it was not constrained by the parent framework element.
            canvasStyle.height = sizeToApply.Height + "px";

            // Get the framework element size after the initial rendering:
            if (frameworkElementWidthWasSpecified && frameworkElementHeightWasSpecified)
            {
                shapeActualSize = new Size(frameworkElementWidth, frameworkElementHeight);
            }
            else
            {
                shapeActualSize = frameworkElement.INTERNAL_GetActualWidthAndHeight(); //Note: in case that the framework element is constrained, it won't take the size of its canvas2d content, so we then resize the canvas2d content so that the shape stretches.
                if (frameworkElementWidthWasSpecified)
                {
                    shapeActualSize.Width = frameworkElementWidth;
                }
                if (frameworkElementHeightWasSpecified)
                {
                    shapeActualSize.Height = frameworkElementHeight;
                }
            }

            if (!frameworkElementWidthWasSpecified || !frameworkElementHeightWasSpecified)
            {
                // Here is the trick:
                //  the element should try to get the size ("separately" in width and height) that is closest to its prefered size (which has been defined in sizeToApply).
                //  to do that, we put the canvas at the prefered size, then we make it take the size of the container (the container is the div that contains the canvas, it is also the Shape's OuterDomElement):
                //      - the first step will make the container take the size it is allowed to that is closest to the prefered size of the element
                //      - the second step will change the canvas' size to the container's size so that the canvas also takes the allowed size closest to its prefered size.

                if (!frameworkElementWidthWasSpecified)
                {
                    canvasStyle.width = shapeActualSize.Width + "px";
                    INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "width", shapeActualSize.Width + 1); //todo: add StrokeThickness instead of +1?
                }
                if (!frameworkElementHeightWasSpecified)
                {
                    canvasStyle.height = shapeActualSize.Height + "px";
                    INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", shapeActualSize.Height + 1); //todo: add StrokeThickness instead of +1?
                }
            }

            dynamic context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            context.translate(0.5, 0.5); //makes is less blurry for some reason.
        }
예제 #4
0
        internal void OnTextDecorationsChanged(TextDecorations?tdc)
        {
            string cssValue = TextDecorationsToHtmlString(tdc);

            INTERNAL_HtmlDomManager.GetDomElementStyleForModification(INTERNAL_OptionalSpecifyDomElementConcernedByFocus).textDecoration = cssValue;
        }
예제 #5
0
        internal void OnTextDecorationsChanged(TextDecorationCollection tdc)
        {
            string cssValue = tdc?.ToHtmlString() ?? string.Empty;

            INTERNAL_HtmlDomManager.GetDomElementStyleForModification(INTERNAL_OptionalSpecifyDomElementConcernedByFocus).textDecoration = cssValue;
        }
예제 #6
0
        public override object CreateDomChildWrapper(object parentRef, out object domElementWhereToPlaceChild)
        {
            if (Orientation == Orientation.Horizontal)
            {
                //------v1------//


                //NOTE: here, we are in a table

                //wrapper for each child:
                //<td style="padding:0px">
                //  <div style="width: inherit;position:relative">
                //      ...(child)
                //  </div>
                //</td>

                //var td = INTERNAL_HtmlDomManager.CreateDomElement("td");
                //td.style.position = "relative";
                //td.style.padding = "0px";
                ////var div = INTERNAL_HtmlDomManager.CreateDomElement("div");
                ////div.style.height = "inherit"; //todo: find a way to make this div actually inherit the height of the td... (otherwise we cannot set its verticalAlignment)
                ////div.style.position = "relative";
                ////INTERNAL_HtmlDomManager.AppendChild(td, div);

                //domElementWhereToPlaceChild = td;

                //return td;



                //------v2------// = better because we only use divs, it's more simple and verticalAlignment.Stretch works when the stackPanel's size is hard coded (but it still doesn't work when it's not).


                //wrapper for each child - v2
                //<div style="display: table-cell;height:inherit;>
                // ...
                //</div>

                var div      = INTERNAL_HtmlDomManager.CreateDomElementAndAppendIt("div", parentRef, this);
                var divStyle = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(div);
                divStyle.position      = "relative";
                divStyle.display       = "table-cell";
                divStyle.height        = "100%";   //this allow the stretched items to actually be stretched to the size of the tallest element when the stackpanel's size is only defined by this element.
                divStyle.verticalAlign = "middle"; // We use this as a default value for elements that have a "stretch" vertical alignment

                domElementWhereToPlaceChild = div;


                return(div);
            }
            else if (Orientation == Orientation.Vertical) //when we arrive here, it should always be true but we never know...
            {
                //NOTE: here, we are in a div


                //wrapper for each child:
                //<div style="width: inherit">... </div>

                var div      = INTERNAL_HtmlDomManager.CreateDomElementAndAppendIt("div", parentRef, this);
                var divStyle = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(div);
                divStyle.position = "relative";
                divStyle.width    = "100%"; // Makes it possible to do horizontal alignment of the element that will be the child of this div.

                domElementWhereToPlaceChild = div;
                return(div);
            }
            else
            {
                throw new NotSupportedException();
            }
        }
예제 #7
0
        protected override void OnAfterApplyVerticalAlignmentAndWidth()
        {
            dynamic style = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(this.INTERNAL_OuterDomElement);

            style.display = "inline";
        }
예제 #8
0
        //INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", sizeToApply.Height);

        /// <summary>
        /// Prepares the Shape so that its canvas has the size it should have, depending on its container, content and Stretch mode.
        /// </summary>
        /// <param name="shape">The Shape containing the canvas.</param>
        /// <param name="canvasDomElement">The canvas in the Shape.</param>
        /// <param name="minX">The minimum X-coordinate of the points in the Shape.</param>
        /// <param name="maxX">The maximum X-coordinate of the points in the Shape.</param>
        /// <param name="minY">The minimum Y-coordinate of the points in the Shape.</param>
        /// <param name="maxY">The maximum Y-coordinate of the points in the Shape.</param>
        /// <param name="stretch">The Stretch mode to apply on the Shape</param>
        /// <param name="shapeActualSize"></param>
        internal static void PrepareStretch(Shape shape, object canvasDomElement, double minX, double maxX, double minY, double maxY, Stretch stretch, out Size shapeActualSize)
        {
            var canvasStyle = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(canvasDomElement);

            //Two steps:
            // 1) We get the size the Shape would take if Stretch = None so that we know its prefered size
            // 2) We make the element take the allowed size closest to that prefered size.

            //We get the size the Shape would take if its Stretch mode was Stretch.None:
            //in Stretch.None mode, the size is from 0 to the rightmost poit and bottommost point:
            double sizeX = maxX;
            double sizeY = maxY;

            //in other Stretched modes, the size is from the leftmost point to the rightmost point and from the topmost to the bottommost point:
            if (stretch != Stretch.None)
            {
                sizeX = maxX - minX;
                sizeY = maxY - minY;
            }
            else //we want to add the size of the shape that goes into negative values:
            {
                if (minX < 0)
                {
                    sizeX = maxX - minX;
                }
                if (minY < 0)
                {
                    sizeY = maxY - minY;
                }
            }

            double offset = shape.StrokeThickness > 0 ? shape.StrokeThickness : 1;
            //todo: (?) for the line below, replace the "+ 1" with the StrokeThickness/LineWidth
            Size sizeToApply = new Size(Math.Max(sizeX + offset, 0), Math.Max(sizeY + offset, 0)); //example: a vertical line still needs 1 pixel width

            //we apply the possible defined size of the outerDomElement of the shape:
            var    style = INTERNAL_HtmlDomManager.GetFrameworkElementOuterStyleForModification(shape);
            bool   frameworkElementWidthWasSpecified = false;
            double frameworkElementWidth             = shape.Width;
            double frameworkElementHeight            = shape.Height;

            if (!double.IsNaN(frameworkElementWidth))
            {
                frameworkElementWidthWasSpecified = true;
                sizeToApply.Width = frameworkElementWidth + offset;
                style.width       = sizeToApply.Width.ToInvariantString() + "px";
            }
            bool frameworkElementHeightWasSpecified = false;

            if (!double.IsNaN(frameworkElementHeight))
            {
                frameworkElementHeightWasSpecified = true;
                sizeToApply.Height = frameworkElementHeight + offset;
                style.height       = sizeToApply.Height.ToInvariantString() + "px";
            }

            if (frameworkElementWidthWasSpecified && frameworkElementHeightWasSpecified)
            {
                shapeActualSize = new Size(frameworkElementWidth, frameworkElementHeight);

                //We apply the size defined earlier (size either by the Width and/or Height of the Shape (when they are set) or by the width and/or height of its content):
                INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "width", sizeToApply.Width);
                INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", sizeToApply.Height);

                canvasStyle.width  = sizeToApply.Width.ToInvariantString() + "px"; // The "sizeToApply" is the size that the shape would take if it was not constrained by the parent framework element.
                canvasStyle.height = sizeToApply.Height.ToInvariantString() + "px";
            }
            else
            {
                if (shape.IsUnderCustomLayout == false)
                {
                    //We apply the size defined earlier (size either by the Width and/or Height of the Shape (when they are set) or by the width and/or height of its content):
                    INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "width", sizeToApply.Width);
                    INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", sizeToApply.Height);

                    canvasStyle.width  = sizeToApply.Width.ToInvariantString() + "px"; // The "sizeToApply" is the size that the shape would take if it was not constrained by the parent framework element.
                    canvasStyle.height = sizeToApply.Height.ToInvariantString() + "px";

                    shapeActualSize = shape.INTERNAL_GetActualWidthAndHeight(); //Note: in case that the framework element is constrained, it won't take the size of its canvas2d content, so we then resize the canvas2d content so that the shape stretches.

                    if (!frameworkElementWidthWasSpecified)
                    {
                        canvasStyle.width = shapeActualSize.Width.ToInvariantString() + "px";
                        INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "width", shapeActualSize.Width + offset);
                    }
                    if (!frameworkElementHeightWasSpecified)
                    {
                        canvasStyle.height = shapeActualSize.Height.ToInvariantString() + "px";
                        INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", shapeActualSize.Height + offset);
                    }
                }
                else
                {
                    shapeActualSize = shape.VisualBounds.Size;

                    if (!frameworkElementWidthWasSpecified)
                    {
                        canvasStyle.width = shapeActualSize.Width.ToInvariantString() + "px";
                        INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "width", shapeActualSize.Width + offset);
                    }
                    else
                    {
                        shapeActualSize.Width = frameworkElementWidth;
                        INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "width", sizeToApply.Width);
                        canvasStyle.width = sizeToApply.Width.ToInvariantString() + "px";
                    }

                    if (!frameworkElementHeightWasSpecified)
                    {
                        canvasStyle.height = shapeActualSize.Height.ToInvariantString() + "px";
                        INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", shapeActualSize.Height + offset);
                    }
                    else
                    {
                        shapeActualSize.Height = frameworkElementHeight;
                        INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", sizeToApply.Height);
                        canvasStyle.height = sizeToApply.Height.ToInvariantString() + "px";
                    }
                }
            }

            var context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            context.translate(0.5, 0.5); //makes is less blurry for some reason.
        }