tags:

views:

3847

answers:

4

It's easy to set CSSClass in the codebehind, 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 then I equally need to change the same element to ReadOnly = false; so I need to remove the CSSClass i set, without killing off any other styles that might be applied.

What's the best way to do this?

A: 

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.

Al W
+6  A: 

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.

AnthonyWJones
The RemoveCssClass will not work if you are removing the original CSS style.
John_
@John: Quite so and I did allude to that "RemoveCssClass is designed to remove only those classes added by AddCssClass".
AnthonyWJones
Fair play I did skim over the rest of your text.
John_
+5  A: 

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();
        }
    }
John_
excellent, thanks
nailitdown
By extracting a method from the split/manipulate/join code and creating a second extension method for `this HtmlControl control` using `control.Attributes("class")` instead of `control.CssClass`, you can extend this ability to generic HTML controls that have runat="server" added to them as well.
patridge
This will add a duplicate class to the list if `AddCssClass()` is called on a string that already contains that class.
Dan Herbert
Looks like you just want `string.Join` instead of defining `ToDelimitedString`!
Noldorin
A: 

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();
}
Chris