/// <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);
                }
            }
        }
Ejemplo n.º 2
0
        /// <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);
                    }
                }
            }
        }