/// <summary> /// This method propagates the styles in the resources associated with /// a framework element to its descendents. This results in a /// style inheritance that mimics WPF's behavior. /// </summary> /// <param name="element">The element that will have its styles /// propagated to its children.</param> /// <param name="recurse">Whether to recurse over styled elements that /// are set to OneTime and have already been styled.</param> private static void PropagateStyles(FrameworkElement element, bool recurse) { BaseMergedStyleDictionary initialDictionary = GetMergedStyleDictionary(element); // Create stream of elements and their base merged style // dictionaries by traversing the logical tree. IEnumerable <Tuple <FrameworkElement, BaseMergedStyleDictionary> > elementsToStyleAndDictionaries = FunctionalProgramming.TraverseDepthFirst( new Tuple <FrameworkElement, BaseMergedStyleDictionary>(element, initialDictionary), (elementAndDictionary) => elementAndDictionary .First .GetLogicalChildrenDepthFirst() .Select(childElement => new Tuple <FrameworkElement, BaseMergedStyleDictionary>( childElement, new MergedStyleResourceDictionary( ImplicitStyleManager.GetExternalResourceDictionary(childElement) ?? childElement.Resources, elementAndDictionary.Second))), (elementAndDictionary) => recurse || (ImplicitStyleManager.GetApplyMode(elementAndDictionary.First) != ImplicitStylesApplyMode.OneTime || !ImplicitStyleManager.GetHasBeenStyled(elementAndDictionary.First))); foreach (Tuple <FrameworkElement, BaseMergedStyleDictionary> elementToStyleAndDictionary in elementsToStyleAndDictionaries) { FrameworkElement elementToStyle = elementToStyleAndDictionary.First; BaseMergedStyleDictionary styleDictionary = elementToStyleAndDictionary.Second; bool styleApplied = false; if (elementToStyle.Style == null || GetStyle(elementToStyle) == elementToStyle.Style) { Style style = styleDictionary[GetStyleKey(elementToStyle)]; if (style != null) { SetStyle(elementToStyle, style); styleApplied = true; } } if (ImplicitStyleManager.GetApplyMode(elementToStyle) == ImplicitStylesApplyMode.OneTime && (VisualTreeHelper.GetChildrenCount(elementToStyle) > 0 || styleApplied)) { ImplicitStyleManager.SetHasBeenStyled(elementToStyle, true); } } }
/// <summary> /// Retrieves all the logical children of a framework element using a /// depth-first search. A visual element is assumed to be a logical /// child of another visual element if they are in the same namescope. /// For performance reasons this method manually manages the stack /// instead of using recursion. /// </summary> /// <param name="parent">The parent framework element.</param> /// <returns>The logical children of the framework element.</returns> internal static IEnumerable <FrameworkElement> GetLogicalChildrenDepthFirst(this FrameworkElement parent) { Debug.Assert(parent != null, "The parent cannot be null."); EnsureName(parent); Popup popup = parent as Popup; if (popup != null) { FrameworkElement popupChild = popup.Child as FrameworkElement; if (popupChild != null) { yield return(popupChild); } } // If control is an items control find the items host panel and // return it if an ItemsPanel template is specified. This works // around a bug which moves the items host into a different name // scope than the items control when an items template is provided. ItemsControl itemsControl = parent as ItemsControl; if (itemsControl != null && itemsControl.ItemsPanel != null) { ItemsPresenter itemsPresenter = itemsControl .GetVisualChildren() .SelectMany(child => FunctionalProgramming.TraverseBreadthFirst( child, node => node.GetVisualChildren(), node => !(node is ItemsControl))) .OfType <ItemsPresenter>() .FirstOrDefault(); if (itemsPresenter != null) { Panel itemsHost = itemsPresenter.GetVisualChildren().OfType <Panel>().FirstOrDefault(); if (itemsHost != null) { yield return(itemsHost); } } } string parentName = parent.Name; Stack <FrameworkElement> stack = new Stack <FrameworkElement>(parent.GetVisualChildren().OfType <FrameworkElement>()); while (stack.Count > 0) { FrameworkElement element = stack.Pop(); if (element.FindName(parentName) == parent || element is UserControl) { yield return(element); } else { foreach (FrameworkElement visualChild in element.GetVisualChildren().OfType <FrameworkElement>()) { stack.Push(visualChild); } } } }