|
|||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionWhen developing controls for a designer environment like Visual Studio or WebMatrix, the complexities of persisting control properties as serialized HTML can come into play. In many cases, the built-in serialization of control properties as attributes or nested child tags is sufficient. There are also several code attributes available to a control developer to apply a degree of customization for this process. In some cases however, a developer requires a greater degree of control over how control properties are persisted as HTML. In this article, I present a custom ASP.NET server control for displaying color choices in a dropdown list. Following a description of the control, I will focus on the problem of persisting a custom collection of items in the context of the Visual Studio Web Form designer, and offer a solution using custom HtmlColorDropDown ControlThe
The The
The selected item is available as a Note that the proper display of foreground or background colors rendered in The default event for the control is <%@ Page language="c#" %>
<%@ Register TagPrefix="cc1" Namespace="UNLV.IAP.WebControls"
Assembly="UNLV.IAP.WebControls.HtmlColorDropDown" %>
<script runat="server">
private void HtmlColorDropDown1_ColorChanged(object sender,
System.EventArgs e)
{
Label1.Text = HtmlColorDropDown1.SelectedColorName;
}
</script>
<html>
<head>
<title>Example</title>
</head>
<body>
<form runat="server">
<cc1:HtmlColorDropDown id="HtmlColorDropDown1" runat="server"
DisplaySelectColorItemText="--Select a Color--"
DisplaySelectColorItem="True"
AutoPostBack="True"
OnColorChanged="HtmlColorDropDown1_ColorChanged">
</cc1:HtmlColorDropDown>
<P>The selected color is: <asp:Label id="Label1" runat="server"/></P>
</form>
</body>
</html>
See the downloadable control documentation for a complete description of all The Issue: Persisting the Collection of UserDefinedColorsThis control was designed with both visual designer (e.g., Visual Studio) and text editor (e.g., Notepad) environments in mind. For designer environments, we inherit much functionality without any extra code. Because we're using regular Likewise, as we have standard A problem occurs however when it comes time to serialize this color collection into the server tag HTML. Typically, we would set the [
PersistenceMode(PersistenceMode.InnerDefaultProperty)
,DesignerSerializationVisibility(
DesignerSerializationVisibility.Content)
]
public ColorCollection UserDefinedColors
{
get {...}
set {...}
}
With these attributes set, we can get the <cc1:htmlcolordropdown id="HtmlColorDropDown1" runat="server"
Palette="UserDefined">
<System.Drawing.Color IsEmpty="False" A="255" B="0" IsNamedColor="True"
IsKnownColor="True" Name="Red" G="0" R="255" IsSystemColor="False">
</System.Drawing.Color>
<System.Drawing.Color IsEmpty="False" A="255" B="0" IsNamedColor="True"
IsKnownColor="True" Name="Green" G="128" R="0" IsSystemColor="False">
</System.Drawing.Color>
<System.Drawing.Color IsEmpty="False" A="255" B="255" IsNamedColor="True"
IsKnownColor="True" Name="Blue" G="0" R="0" IsSystemColor="False">
</System.Drawing.Color>
</cc1:htmlcolordropdown>
The problem isn't only in the fact that there is much more information about the colors persisted than we need or want. As the attributes represent read-only properties of the <cc1:htmlcolordropdown id="HtmlColorDropDown1" runat="server"
Palette="UserDefined">
<Color value="Red"/>
<Color value="Green"/>
<Color value="Blue"/>
</cc1:htmlcolordropdown>
This also makes the control easier to work with for those using plain text editors. A custom Custom Persistence through a ControlDesignerIn order to persist the For the public class HtmlColorDropDownDesigner : ControlDesigner
{
public override string GetPersistInnerHtml()
{
StringWriter sw = new StringWriter();
HtmlTextWriter html = new HtmlTextWriter(sw);
HtmlColorDropDown dd
= this.Component as HtmlColorDropDown;
if (dd != null)
{
// for each color in the collection, output its
// html known name (if it is a known color)
// or its html hex string representation
// in the format:
// <Color value='xxx' />
foreach(Color c in dd.UserDefinedColors)
{
string s =
(c.IsKnownColor ? c.Name
: ColorUtility.ColorToHexString(c) );
html.WriteBeginTag("Color");
html.WriteAttribute("value", s);
html.WriteLine(HtmlTextWriter.SelfClosingTagEnd);
}
}
return sw.ToString();
}
}
In the overridden <Color value="xxx">
where xxx is either the name of the color (for known color items such as "Red") or its HTML hex string (e.g., "#FF0000"). Through this custom persistence, we can represent the full It is worthwhile to note that other methods are available for customizing how a control's properties are to be persisted. A The custom designer is associated with the main [
//...(other attributes)...//
,PersistChildren(false)
,Designer(typeof(HtmlColorDropDownDesigner))
]
public class HtmlColorDropDown : Control, IPostBackDataHandler
, IPostBackEventHandler, IAttributeAccessor
{
...
[
//...(other attributes)...//
,PersistenceMode(PersistenceMode.InnerDefaultProperty)
,DesignerSerializationVisibility(
DesignerSerializationVisibility.Content)
]
public ColorCollection UserDefinedColors
{
get {...}
set {...}
}
...
}
Custom Parsing through a ControlBuilderThe custom The first of the three is a subclass of public class HtmlColorDropDownBuilder : ControlBuilder
{
public override Type GetChildControlType(string tagName,
IDictionary attribs)
{
if (string.Compare(tagName,"color", true) == 0)
{
return typeof(ColorItemHelper);
}
return base.GetChildControlType (tagName, attribs);
}
}
The custom builder's public class ColorItemHelper
{
private string _value;
public string Value
{
get {return _value;}
set {_value = value;}
}
}
The custom builder is assigned to the [
//...(other attributes)...//
, ParseChildren(false)
, ControlBuilder(typeof(HtmlColorDropDownBuilder))
]
public class HtmlColorDropDown : Control, IPostBackDataHandler
, IPostBackEventHandler, IAttributeAccessor
{
...
protected override void AddParsedSubObject(object obj)
{
if (obj is ColorItemHelper)
{
ColorItemHelper h = obj as ColorItemHelper;
this.UserDefinedColors.Add(h.Value);
}
else
base.AddParsedSubObject (obj);
}
...
}
Note that the SummaryThe | ||||||||||||||||||||||||||||||||||||