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