private List <StyleMatchInfo> UpdateMatchingStyles(TUIElement styleResourceReferenceHolder, StyleSheet styleSheet, TUIElement startFrom) { var requiredStyleInfos = new List <StyleMatchInfo>(); IDomElement <TDependencyObject> root = null; IDomElement <TDependencyObject> visualTree = null; IDomElement <TDependencyObject> logicalTree = null; foreach (var rule in styleSheet.Rules) { if (rule.SelectorType == SelectorType.VisualTree) { if (visualTree == null) { visualTree = treeNodeProvider.GetDomElement(startFrom ?? styleResourceReferenceHolder); visualTree.XamlCssStyleSheets.Clear(); visualTree.XamlCssStyleSheets.Add(styleSheet); } root = visualTree; } else { if (logicalTree == null) { logicalTree = treeNodeProvider.GetDomElement(startFrom ?? styleResourceReferenceHolder); logicalTree.XamlCssStyleSheets.Clear(); logicalTree.XamlCssStyleSheets.Add(styleSheet); } root = logicalTree; } // apply our selector var matchedNodes = root.QuerySelectorAllWithSelf(rule.SelectorString) .Where(x => x != null) .Cast <IDomElement <TDependencyObject> >() .Where(x => treeNodeProvider.GetParent(x.Element) != null) // workaround WPF: somehow dom-tree is out of sync with UI-tree!?! .ToList(); var otherStyleElements = matchedNodes .Where(x => { var parent = GetStyleSheetParent(x.Element); // parent happens to be null if class was changed by binding if (parent == null) { return(true); } var elementStyleSheet = dependencyPropertyService.GetStyleSheet(parent); return(elementStyleSheet != null && elementStyleSheet != styleSheet); }).ToList(); matchedNodes = matchedNodes.Except(otherStyleElements).ToList(); // Debug.WriteLine($"matchedNodes: ({matchedNodes.Count}) " + string.Join(", ", matchedNodes.Select(x => x.Id))); var matchedElementTypes = matchedNodes .Select(x => x.Element.GetType()) .Distinct() .ToList(); // Debug.WriteLine($"Matched Types: ({matchedElementTypes.Count}) " + string.Join(", ", matchedElementTypes.Select(x => x.Name))); foreach (var matchingNode in matchedNodes) { var element = matchingNode.Element; var matchingStyles = dependencyPropertyService.GetMatchingStyles(element) ?? new string[0]; var resourceKey = nativeStyleService.GetStyleResourceKey(styleSheet.Id, element.GetType(), rule.SelectorString); dependencyPropertyService.SetMatchingStyles(element, matchingStyles.Concat(new[] { resourceKey }).Distinct().ToArray()); if (requiredStyleInfos.Any(x => x.Rule == rule && x.MatchedType == element.GetType()) == false) { requiredStyleInfos.Add(new StyleMatchInfo { Rule = rule, MatchedType = element.GetType() }); } } } return(requiredStyleInfos); }
private static IList <IDomElement <TDependencyObject, TDependencyProperty> > UpdateMatchingStyles( StyleSheet styleSheet, IDomElement <TDependencyObject, TDependencyProperty> startFrom, Dictionary <TDependencyObject, StyleUpdateInfo> styleUpdateInfos, IDependencyPropertyService <TDependencyObject, TStyle, TDependencyProperty> dependencyPropertyService, INativeStyleService <TStyle, TDependencyObject, TDependencyProperty> nativeStyleService) { // var requiredStyleInfos = new List<StyleMatchInfo>(); var found = new HashSet <IDomElement <TDependencyObject, TDependencyProperty> >(); if (startFrom == null || !startFrom.IsReady) { return(found.ToList()); } if (startFrom.StyleInfo.DoMatchCheck == SelectorType.None) { return(new List <IDomElement <TDependencyObject, TDependencyProperty> >()); } startFrom.XamlCssStyleSheets.Clear(); startFrom.XamlCssStyleSheets.Add(styleSheet); var traversed = SelectorType.None; foreach (var rule in styleSheet.Rules) { // // Debug.WriteLine($"--- RULE {rule.SelectorString} ----"); // apply our selector var type = SelectorType.LogicalTree; if (rule.Selectors[0].StartOnVisualTree()) { type = SelectorType.VisualTree; } if ((type == SelectorType.LogicalTree && !startFrom.IsInLogicalTree) || (type == SelectorType.VisualTree && !startFrom.IsInVisualTree) ) { continue; } traversed |= type; var matchedNodes = startFrom.QuerySelectorAllWithSelf(styleSheet, rule.Selectors[0], type) .Where(x => x != null) .Cast <IDomElement <TDependencyObject, TDependencyProperty> >() .ToList(); var matchedElementTypes = matchedNodes .Select(x => x.Element.GetType()) .Distinct() .ToList(); foreach (var matchingNode in matchedNodes) { var element = matchingNode.Element; if (!found.Contains(matchingNode)) { found.Add(matchingNode); } matchingNode.StyleInfo.CurrentMatchedSelectors.Add(rule.Selectors[0]); var initialStyle = dependencyPropertyService.GetInitialStyle(element); var discriminator = initialStyle != null?initialStyle.GetHashCode().ToString() : ""; var resourceKey = nativeStyleService.GetStyleResourceKey(styleSheet.Id + discriminator, element.GetType(), rule.SelectorString); //var resourceKey = nativeStyleService.GetStyleResourceKey(rule.StyleSheetId, element.GetType(), rule.SelectorString); if (!matchingNode.StyleInfo.CurrentMatchedResourceKeys.Contains(resourceKey)) { matchingNode.StyleInfo.CurrentMatchedResourceKeys.Add(resourceKey); } } } foreach (var f in found) { f.StyleInfo.DoMatchCheck = SelectorType.None; f.StyleInfo.CurrentMatchedSelectors = f.StyleInfo.CurrentMatchedSelectors.Distinct() .OrderBy(x => x.IdSpecificity) .ThenBy(x => x.ClassSpecificity) .ThenBy(x => x.SimpleSpecificity) .ToList() .ToLinkedHashSet(); } if ((traversed & SelectorType.VisualTree) > 0) { SetDoMatchCheckToNoneInSubTree(startFrom, styleSheet, SelectorType.VisualTree); } if ((traversed & SelectorType.LogicalTree) > 0) { SetDoMatchCheckToNoneInSubTree(startFrom, styleSheet, SelectorType.LogicalTree); } return(found.ToList()); }
private List <StyleMatchInfo> UpdateMatchingStyles(TUIElement styleResourceReferenceHolder, StyleSheet styleSheet, TUIElement startFrom) { var requiredStyleInfos = new List <StyleMatchInfo>(); IDomElement <TDependencyObject> root = null; IDomElement <TDependencyObject> visualTree = null; IDomElement <TDependencyObject> logicalTree = null; foreach (var rule in styleSheet.Rules) { if (rule.SelectorType == SelectorType.VisualTree) { if (visualTree == null) { visualTree = treeNodeProvider.GetDomElement(startFrom ?? styleResourceReferenceHolder); visualTree.XamlCssStyleSheets.Clear(); visualTree.XamlCssStyleSheets.Add(styleSheet); } root = visualTree; } else { if (logicalTree == null) { logicalTree = treeNodeProvider.GetDomElement(startFrom ?? styleResourceReferenceHolder); logicalTree.XamlCssStyleSheets.Clear(); logicalTree.XamlCssStyleSheets.Add(styleSheet); } root = logicalTree; } // apply our selector var matchedNodes = root.QuerySelectorAllWithSelf(rule.SelectorString) .Where(x => x != null) .Cast <IDomElement <TDependencyObject> >() .ToList(); // Debug.WriteLine($"matchedNodes: ({matchedNodes.Count}) " + string.Join(", ", matchedNodes.Select(x => x.Id))); var matchedElementTypes = matchedNodes .Select(x => x.Element.GetType()) .Distinct() .ToList(); // Debug.WriteLine($"Matched Types: ({matchedElementTypes.Count}) " + string.Join(", ", matchedElementTypes.Select(x => x.Name))); foreach (var matchingNode in matchedNodes) { var element = matchingNode.Element; var matchingStyles = dependencyPropertyService.GetMatchingStyles(element) ?? new string[0]; var resourceKey = nativeStyleService.GetStyleResourceKey(element.GetType(), rule.SelectorString); dependencyPropertyService.SetMatchingStyles(element, matchingStyles.Concat(new[] { resourceKey }).Distinct().ToArray()); if (requiredStyleInfos.Any(x => x.Rule == rule && x.MatchedType == element.GetType()) == false) { requiredStyleInfos.Add(new StyleMatchInfo { Rule = rule, MatchedType = element.GetType() }); } } } return(requiredStyleInfos); }
private List <StyleMatchInfo> UpdateMatchingStyles(TUIElement styleResourceReferenceHolder, StyleSheet styleSheet, TUIElement startFrom) { var requiredStyleInfos = new List <StyleMatchInfo>(); IDomElement <TDependencyObject> root = null; IDomElement <TDependencyObject> visualTree = null; IDomElement <TDependencyObject> logicalTree = null; foreach (var rule in styleSheet.Rules) { // Debug.WriteLine($"--- RULE {rule.SelectorString} ----"); if (rule.SelectorType == SelectorType.VisualTree) { treeNodeProvider.Switch(SelectorType.VisualTree); if (visualTree == null) { visualTree = treeNodeProvider.GetDomElement(startFrom ?? styleResourceReferenceHolder); visualTree.XamlCssStyleSheets.Clear(); visualTree.XamlCssStyleSheets.Add(styleSheet); } root = visualTree; } else { treeNodeProvider.Switch(SelectorType.LogicalTree); if (logicalTree == null) { if (!treeNodeProvider.IsInTree(startFrom ?? styleResourceReferenceHolder)) { continue; } logicalTree = treeNodeProvider.GetDomElement(startFrom ?? styleResourceReferenceHolder); logicalTree.XamlCssStyleSheets.Clear(); logicalTree.XamlCssStyleSheets.Add(styleSheet); } root = logicalTree; } // apply our selector var matchedNodes = root.QuerySelectorAllWithSelf(rule.SelectorString) .Where(x => x != null) .Cast <IDomElement <TDependencyObject> >() .ToList(); var otherStyleElements = matchedNodes .Where(x => { var parent = GetStyleSheetParent(x.Element); // parent happens to be null if class was changed by binding if (parent == null) { return(true); } var elementStyleSheet = dependencyPropertyService.GetStyleSheet(parent); return(elementStyleSheet != null && elementStyleSheet != styleSheet); }).ToList(); matchedNodes = matchedNodes.Except(otherStyleElements).ToList(); var matchedElementTypes = matchedNodes .Select(x => x.Element.GetType()) .Distinct() .ToList(); foreach (var matchingNode in matchedNodes) { var element = matchingNode.Element; var oldMatchingStyles = dependencyPropertyService.GetMatchingStyles(element) ?? new string[0]; var resourceKey = nativeStyleService.GetStyleResourceKey(styleSheet.Id, element.GetType(), rule.SelectorString); var newMatchingStyles = oldMatchingStyles.Concat(new[] { resourceKey }).Distinct() .Select(x => new { key = x, selector = new Selector { Value = x.Split('{')[1] } }) .OrderBy(x => x.selector.IdSpecificity) .ThenBy(x => x.selector.ClassSpecificity) .ThenBy(x => x.selector.SimpleSpecificity) .ToArray(); var newMatchingStylesStrings = newMatchingStyles.Select(x => x.key).ToArray(); // Debug.WriteLine($"'{rule.SelectorString}' {GetPath(matchingNode)}: " + string.Join("|", newMatchingStylesStrings)); dependencyPropertyService.SetMatchingStyles(element, newMatchingStylesStrings); if (requiredStyleInfos.Any(x => x.Rule == rule && x.MatchedType == element.GetType()) == false) { requiredStyleInfos.Add(new StyleMatchInfo { Rule = rule, MatchedType = element.GetType() }); } } } return(requiredStyleInfos); }
private static IList <IDomElement <TDependencyObject> > UpdateMatchingStyles( StyleSheet styleSheet, IDomElement <TDependencyObject> startFromLogical, IDomElement <TDependencyObject> startFromVisual, Dictionary <TDependencyObject, StyleUpdateInfo> styleUpdateInfos, IDependencyPropertyService <TDependencyObject, TStyle, TDependencyProperty> dependencyPropertyService, INativeStyleService <TStyle, TDependencyObject, TDependencyProperty> nativeStyleService) { // var requiredStyleInfos = new List<StyleMatchInfo>(); IDomElement <TDependencyObject> root = null; IDomElement <TDependencyObject> visualTree = null; IDomElement <TDependencyObject> logicalTree = null; var found = new List <IDomElement <TDependencyObject> >(); if (startFromVisual?.StyleInfo.DoMatchCheck == SelectorType.None || startFromLogical?.StyleInfo.DoMatchCheck == SelectorType.None) { return(new List <IDomElement <TDependencyObject> >()); } return($"{startFromLogical?.GetPath() ?? startFromVisual?.GetPath() ?? "NULL!?!"}".Measure(() => { foreach (var rule in styleSheet.Rules) { $"{rule.SelectorString}".Measure(() => { // // Debug.WriteLine($"--- RULE {rule.SelectorString} ----"); if (rule.SelectorType == SelectorType.VisualTree) { if (startFromVisual == null) { //continue; return; } if (visualTree == null) { visualTree = startFromVisual; visualTree?.XamlCssStyleSheets.Clear(); visualTree?.XamlCssStyleSheets.Add(styleSheet); } root = visualTree; } else { if (startFromLogical == null) { //continue; return; } if (logicalTree == null) { logicalTree = startFromLogical; logicalTree?.XamlCssStyleSheets.Clear(); logicalTree?.XamlCssStyleSheets.Add(styleSheet); } root = logicalTree; } if (root == null) { //continue; return; } // apply our selector var matchedNodes = "QuerySelectorAllWithSelf".Measure(() => root.QuerySelectorAllWithSelf(styleSheet, rule.Selectors[0]) .Where(x => x != null) .Cast <IDomElement <TDependencyObject> >() .ToList()); var matchedElementTypes = matchedNodes .Select(x => x.Element.GetType()) .Distinct() .ToList(); $"foreach {matchedNodes.Count}".Measure(() => { foreach (var matchingNode in matchedNodes) { var element = matchingNode.Element; if (!found.Contains(matchingNode)) { found.Add(matchingNode); } var discriminator = "GetInitialStyle".Measure(() => dependencyPropertyService.GetInitialStyle(element) != null ? element.GetHashCode().ToString() : ""); var resourceKey = "GetStyleResourceKey".Measure(() => nativeStyleService.GetStyleResourceKey(styleSheet.Id + discriminator, element.GetType(), rule.SelectorString)); //var resourceKey = nativeStyleService.GetStyleResourceKey(rule.StyleSheetId, element.GetType(), rule.SelectorString); if (!matchingNode.StyleInfo.CurrentMatchedSelectors.Contains(resourceKey)) { matchingNode.StyleInfo.CurrentMatchedSelectors.Add(resourceKey); } } }); }); } "found".Measure(() => { found = found.Distinct().ToList(); foreach (var f in found) { f.StyleInfo.DoMatchCheck = SelectorType.None; f.StyleInfo.CurrentMatchedSelectors = f.StyleInfo.CurrentMatchedSelectors.Distinct().Select(x => new { key = x, SpecificityResult = SpecificityCalculator.Calculate(x.Split('{')[1]) }) .OrderBy(x => x.SpecificityResult.IdSpecificity) .ThenBy(x => x.SpecificityResult.ClassSpecificity) .ThenBy(x => x.SpecificityResult.SimpleSpecificity) .ToList() .Select(x => x.key) .ToList(); } }); "SetDoMatchCheckToNoneInSubTree".Measure(() => { SetDoMatchCheckToNoneInSubTree(startFromLogical, styleSheet); SetDoMatchCheckToNoneInSubTree(startFromVisual, styleSheet); }); return found; })); }