NestedStyleSelector implementation

3 posts, 0 answers
  1. Art
    Art avatar
    23 posts
    Member since:
    Apr 2015

    Posted 02 Jun Link to this post

    I hope that someone will find this as useful as it can be.

    Purpose:

    Can apply many StyleSelectors to one item by cascade.

    public abstract class NestedStyleSelector : StyleSelector
    {
        public StyleSelector ChildStyleSelector { get; set; }
     
        // Use this instead of the SelectStyle method
        //
        public abstract Style GetStyle(object item, DependencyObject container);
     
        public sealed override Style SelectStyle(object item, DependencyObject container)
        {
            Style currentStyle = GetStyle(item, container),
                  childStyle = null;
     
            if (ChildStyleSelector != null)
            {
                childStyle = ChildStyleSelector.SelectStyle(item, container);
            }
     
            if (childStyle != null)
            {
                if (currentStyle != null && currentStyle.TargetType != childStyle.TargetType)
                    throw new InvalidOperationException();
     
                var clonnedStyle = new Style(childStyle.TargetType)
                {
                    BasedOn = currentStyle
                };
     
                foreach (var setterBase in childStyle.Setters)
                {
                    var setter = setterBase as Setter;
     
                    if (setter == null)
                        continue;
     
                    clonnedStyle.Setters.Add(new Setter
                    {
                        Property = setter.Property,
                        Value = setter.Value
                    });
                }
     
                currentStyle = clonnedStyle;
            }
     
            return currentStyle ?? base.SelectStyle(item, container);
        }
    }

     

    Usage in child implementations:

    <!-- Some class, that implements the NestedStyleSelector -->
    <c:NestedStyleSelector>
        <c:NestedStyleSelector.ChildStyleSelector>
            <!-- Any another style selector -->
        </cNestedStyleSelector.ChildStyleSelector>
    </c:NestedStyleSelector>

    Restrictions:

    - TargetType of all styles in chain must equals with it's parent returned style TargetType.

    - Setter in choosen style of Child StyleSelector overrides the same property of parent style selector.

    - BasedOn can be specified only in a first node declaration.

    It works for me when I combine decisions, which row can be expanded and wich row has alternating background.

     

    Sorry for my English :)

  2. Art
    Art avatar
    23 posts
    Member since:
    Apr 2015

    Posted 02 Jun Link to this post

    There is strange issue, when setting currentStyle to childStyle (InvalidCastException). I've solved it by "clonning" the currentStyle too, before replacing it by childStyle:

    public abstract class NestedStyleSelector : StyleSelector
    {
        public StyleSelector ChildStyleSelector { get; set; }
     
        public abstract Style GetStyle(object item, DependencyObject container);
     
        public sealed override Style SelectStyle(object item, DependencyObject container)
        {
            Style currentStyle = CloneStyle(GetStyle(item, container)),
                  childStyle = null;
     
            if (ChildStyleSelector != null)
            {
                childStyle = ChildStyleSelector.SelectStyle(item, container);
            }
     
            if (childStyle != null)
            {
                if (currentStyle != null && currentStyle.TargetType != childStyle.TargetType)
                    throw new InvalidOperationException();
     
                childStyle = CloneStyle(childStyle);
                childStyle.BasedOn = currentStyle;
     
                currentStyle = childStyle;
            }
     
            return currentStyle ?? base.SelectStyle(item, container);
        }
     
        private static Style CloneStyle(Style sourceStyle)
        {
            if (sourceStyle == null)
                return null;
     
            var clonnedStyle = new Style(sourceStyle.TargetType)
            {
                BasedOn = sourceStyle.BasedOn
            };
     
            foreach (var setterBase in sourceStyle.Setters)
            {
                var setter = setterBase as Setter;
     
                if (setter == null)
                    continue;
     
                clonnedStyle.Setters.Add(new Setter
                {
                    Property = setter.Property,
                    Value = setter.Value
                });
            }
     
            return clonnedStyle;
        }
    }

  3. DevCraft banner
  4. Stefan X1
    Admin
    Stefan X1 avatar
    523 posts

    Posted 07 Jun Link to this post

    Hello Artur,

    Thank you for sharing this solution with the community. I have updated your Telerik points as a gratitude for your contribution.

    All the best,
    Stefan X1
    Telerik
    Do you need help with upgrading your AJAX, WPF or WinForms project? Check the Telerik API Analyzer and share your thoughts.
Back to Top