/// <summary> /// Call this method to perform the specified action in a Dispatcher.Invoke call, but only /// if another action is not already pending execution. This is useful for example to redraw /// the screen when a collection of item changes, doing so only once if the collection changes /// multiple times. Another example is redrawing an element when any of its properties change, /// while ensuring that if many properties are changed, the element is redrawn only once. /// </summary> /// <param name="action">The action to queue</param> public void QueueActionIfQueueIsEmpty(Action action) { if (_queueIsEmpty) // This ensures that the "QueueAction" method below is only called once, and it is not called again until its delegate has been executed. { _queueIsEmpty = false; INTERNAL_DispatcherHelpers.QueueAction(() => { _queueIsEmpty = true; action(); }); } }
static void AttachVisualChild_Private(UIElement child, UIElement parent, int index) { // // THIS IS WHAT THE FINAL STRUCTURE IN THE DOM TREE WILL LOOK LIKE: // // domElementWhereToPlaceChildStuff // --- [wrapperForChild] // --- --- [innerDivOfWrapperForChild] // --- --- --- [additionalOutsideDivForMargins, aka BoxSizing] // --- --- --- --- outerDomElement // //-------------------------------------------------------- // PREPARE THE PARENT: //-------------------------------------------------------- #if PERFSTAT var t0 = Performance.now(); #endif // Prepare the parent DOM structure so that it is ready to contain the child (for example, in case of a grid, we need to (re)create the rows and columns where to place the elements). //parent.INTERNAL_UpdateDomStructureIfNecessary(); object domElementWhereToPlaceChildStuff = (parent.GetDomElementWhereToPlaceChild(child) ?? parent.INTERNAL_InnerDomElement); // A "wrapper for child" is sometimes needed between the child and the parent (for example in case of a grid). It is usually one or more DIVs that fit in-between the child and the parent, and that are used to position the child within the parent. object innerDivOfWrapperForChild; object wrapperForChild = parent.CreateDomChildWrapper(domElementWhereToPlaceChildStuff, out innerDivOfWrapperForChild, index); bool comparison1 = (wrapperForChild == null); // Note: we need due to a bug of JSIL where translation fails if we do not use this temp variable. bool comparison2 = (innerDivOfWrapperForChild == null); // Note: we need due to a bug of JSIL where translation fails if we do not use this temp variable. bool doesParentRequireToCreateAWrapperForEachChild = (!comparison1 && !comparison2); // Note: The result is "True" for complex structures such as tables, false otherwise (cf. documentation in "INTERNAL_VisualChildInformation" class). #if PERFSTAT Performance.Counter("VisualTreeManager: Prepare the parent", t0); #endif //-------------------------------------------------------- // CONTINUE WITH THE OTHER STEPS (AND DEFER SOME OF THEM WHEN THE ELEMENT IS COLLAPSED): //-------------------------------------------------------- // Defer loading to when the control becomes visible if the option to not load collapsed controls is enabled: if (EnableOptimizationWhereCollapsedControlsAreNotLoaded && child.Visibility == Visibility.Collapsed) { child.INTERNAL_DeferredLoadingWhenControlBecomesVisible = () => { AttachVisualChild_Private_MainSteps( child, parent, doesParentRequireToCreateAWrapperForEachChild, innerDivOfWrapperForChild, domElementWhereToPlaceChildStuff, wrapperForChild); }; } else if (EnableOptimizationWhereCollapsedControlsAreLoadedLast && child.Visibility == Visibility.Collapsed) { child.INTERNAL_DeferredLoadingWhenControlBecomesVisible = () => { AttachVisualChild_Private_MainSteps( child, parent, doesParentRequireToCreateAWrapperForEachChild, innerDivOfWrapperForChild, domElementWhereToPlaceChildStuff, wrapperForChild); }; INTERNAL_DispatcherHelpers.QueueAction(() => { Action deferredLoadingWhenControlBecomesVisible = child.INTERNAL_DeferredLoadingWhenControlBecomesVisible; if (deferredLoadingWhenControlBecomesVisible != null) // Note: it may have become "null" if the visibility was changed to "Visible" before the dispatched was called, in which case the element is loaded earlier (cf. "Visibility_Changed" handler) { child.INTERNAL_DeferredLoadingWhenControlBecomesVisible = null; deferredLoadingWhenControlBecomesVisible(); } }); } else { AttachVisualChild_Private_MainSteps( child, parent, doesParentRequireToCreateAWrapperForEachChild, innerDivOfWrapperForChild, domElementWhereToPlaceChildStuff, wrapperForChild); } }