Change CSS classes from code

2019-01-11 11:57发布

问题:

It's easy to set CssClass in the code-behind, but this runs the risk of overwriting existing classes.

I need to set certain elements to ReadOnly = true; and I'd like to apply a style as a visual cue that the item cannot be altered...easy enough:

.CssClass += " ReadOnlyStyle";

But at times I will also need to change the same element to ReadOnly = false; which means that I will need to remove the CSS class that I set without removing any other styles that I might have assigned.

What's the best way to do this?

回答1:

I've taken AnthonyWJones original code and amended it so that it works no matter what scenario:

static class WebControlsExtensions
    {
        public static void AddCssClass(this WebControl control, string cssClass)
        {
            List<string> classes = control.CssClass.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();

            classes.Add(cssClass);

            control.CssClass = classes.ToDelimitedString(" ");
        }

        public static void RemoveCssClass(this WebControl control, string cssClass)
        {
            List<string> classes = control.CssClass.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();

            classes.Remove(cssClass);

            control.CssClass = classes.ToDelimitedString(" ");
        }
    }

    static class StringExtensions
    {
        public static string ToDelimitedString(this IEnumerable<string> list, string delimiter)
        {
            StringBuilder sb = new StringBuilder();
            foreach (string item in list)
            {
                if (sb.Length > 0)
                    sb.Append(delimiter);

                sb.Append(item);
            }

            return sb.ToString();
        }
    }


回答2:

In C# 3 you can add some extension methods.

 static class WebControlsExtensions
 {
     public static void AddCssClass (this WebControl control, string cssClass)
     {
         control.CssClass += " " + cssClass;
     }
     public static void RemoveCssClass (this WebControl control, string cssClass)
     {
         control.CssClass = control.CssClass.replace(" " + cssClass, "");
     }
 }

Usage:-

ctl.AddCssClass("ReadOnly");
ctl.RemoveCssClass("ReadOnly");

Note the RemoveCssClass is designed to remove only those classes added by AddCssClass and has the limitation that where 2 additional class names is added the shortest name should not match exactly the start of the longest name. E.g., If you added "test" and "test2" you can't remove test without corrupting the CssClass. This could be improved with RegEx by I expect the above to be adequate for your needs.

Note if you don't have C#3 then remove the this keyword from the first parameter and use the static methods in the conventional manner.



回答3:

Related... if you just want to toggle a Class based upon a condition...

bool disable = true;      // this will vary (true/false) based on UI state

string newClass = disable ? "BtnGray" : "BtnPink";

string currentClass = disable ? "BtnPink" : "BtnGray";

myButton.CssClass = myButton.CssClass.Replace( currentClass, newClass );


回答4:

This version checks to make sure the given class isn't already added before adding it.

public static void CssAddClass(this WebControl control, string className)
{
    var classNames = control.CssClass.Split
        (new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

    if (classNames.Contains(className))
    {
        return;
    }

    control.CssClass = string.Concat
        (classNames.Select(name => name + " ").ToArray()) + className;
}

public static void CssRemoveClass(this WebControl control, string className)
{
    var classNames = from name in control.CssClass.
                         Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries)
                     where name != className
                     select name + " ";


    control.CssClass = string.Concat(classNames.ToArray()).TrimEnd();
}


回答5:

I made a version for pre-C#3:

        public static class WebControlsExtensions
        {
            public static void AddCssClass(WebControl control, string cssClass)
            {
                string[] cssClasses = control.CssClass.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                List<string> classes = new List<string>(cssClasses);

                if (!classes.Contains(cssClass)) {
                    classes.Add(cssClass);
                }

                control.CssClass = StringExtensions.ToDelimitedString(classes, " ");
            }

            public static void RemoveCssClass(WebControl control, string cssClass)
            {
                string[] cssClasses = control.CssClass.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                List<string> classes = new List<string>(cssClasses);

                bool removed = true;
                while (removed) {
                    removed = classes.Remove(cssClass);
                }

                control.CssClass = StringExtensions.ToDelimitedString(classes, " ");
            }
    }
    static class StringExtensions {
        public static string ToDelimitedString(List<string> list, string delimiter)
        {
            StringBuilder sb = new StringBuilder();
            foreach (string item in list) {
                if (sb.Length > 0)
                    sb.Append(delimiter);

                sb.Append(item);
            }

            return sb.ToString();
        }
    }

Used like:

WebControlsExtensions.AddCssClass(ctl, "classname");
WebControlsExtensions.RemoveCssClass(ctl, "classname");

This one will only add a class if it's not already there. It will also remove all instances of a class (if, for some reason, there are multiple in there)



回答6:

Pure .NET 2.0 (No extensions! No LINQ! No RegEx! No unnecessary WebControl class!). These methods are quite general to be used not for CSS classes only.

public static string AddCssClass(string classContainer, string className)
    {
        if (string.IsNullOrEmpty(classContainer)) return className ?? string.Empty;
        if (string.IsNullOrEmpty(className)) return classContainer;

        var classNames = classContainer.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
        if (Array.Exists(classNames, delegate(string s) { return s.Equals(className); })) return classContainer;

        return classContainer + " " + className;
    }

    public static string RemoveCssClass(string classContainer, string className)
    {
        if (string.IsNullOrEmpty(classContainer)) return className ?? string.Empty;
        if (string.IsNullOrEmpty(className)) return classContainer;

        var classNames = classContainer.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
        int index = Array.FindIndex(classNames, delegate(string s) { return s.Equals(className); });
        if (index >= 0)
        {
            return string.Join(" ", classNames, 0, index) +
                (   index + 1 < classNames.Length ?
                    " " + string.Join(" ", classNames, index + 1, classNames.Length - index - 1)
                    :
                    string.Empty    );
        }

        return classContainer;
    }

    public static string ToggleCssClass(string classContainer, string className)
    {
        if (string.IsNullOrEmpty(classContainer)) return className ?? string.Empty;
        if (string.IsNullOrEmpty(className)) return classContainer;

        var classNames = classContainer.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

        if (Array.Exists(classNames, delegate(string s) { return s.Equals(className); })) return RemoveCssClass(classContainer, className);

        return classContainer + " " + className;
    }


回答7:

Can you make your own custom classes? Derive from the ASP.NET Button and add a propert for Read only. Somewhere...probably in the OnPreRender, you can check the new property and set (or not set) the CSSClass property accordingly.