Evjen c26.tex V2 - 01/28/2008 3:48pm Page 1211 Chapter 26: User and Server Controls Attribute Description Bindable Indicates that the property can be bound to a data source Browsable Indicates whether the property should be displayed at design time in the Property Browser Category Indicates the category this property should be displayed under in the Property Browser Description Displays a text string at the bottom of the Property Browser that describes the purpose of the property EditorBrowsable Indicates whether the property should be editable when shown in the Property Browser DefaultValue Indicates the default value of the property shown in the Property Browser DesignerSerializationVisibility Specifies the visibility a property has to the design-time serializer NotifyParentProperty Indicates that the parent property is notified when the value of the property is modified PersistChildren Indicates whether, at design-time, the child controls of a server control should be persisted as nested inner controls PersistanceMode Specifies how a property or an event is persisted to the ASP.NET page TemplateContainer Specifies the type of INamingContainer that will contain the template once it is created Editor Indicates the UI Type Editor class this control should use to edit its value Localizable Indicates that the property contains text that can be localized Themable Indicates whether this property can have a theme applied to it The Page Event Lifecycle Before we talk about rendering HTML, you must understand the lifecycle of a Web page. As the control developer, you are responsible for overriding methods that execute during the lifecycle and implement- ing your own custom rendering logic. Remember that when a Web browser makes a request to the server, it is using HTTP, a stateless protocol. ASP.NET provides a page-execution framework that helps create the illusion of state in a Web application. This framework is basically a series of methods and events that execute every time an 1211 Evjen c26.tex V2 - 01/28/2008 3:48pm Page 1212 Chapter 26: User and Server Controls ASP.NET page is processed. You may have seen diagrams showing this lifecycle for ASP.NET 1.0. Since ASP.NET 2.0, a variety of additional events have been available to give you more power over the behavior of the control. Figure 26-6 shows the events and methods called during the control’s lifecycle. Many events and members are executed during the control’s lifecycle, but you should concentrate on the more important among them. Rendering Services The main job of a server control is to render some type of markup language to the HTTP output stream, which is returned to and displayed by the client. If your client is a standard browser, the control should emit HTML; if the client is something like a mobile device, the control may need to emit a different type of markup, such as WAP, or WML. As I stated earlier, it is your responsibility as the control developer to tell the server control what markup to render. The overridden RenderContents method, called during the control’s lifecycle, is the primary location where you tell the control what you want to emit to the client. In Listing 26-12, notice that the RenderContents method is used to tell the control to print the value of the Text property. Listing 26-12: Overriding the Render method VB Protected Overrides Sub RenderContents(ByVal output As HtmlTextWriter) output.Write(Text) End Sub C# protected override void RenderContents(HtmlTextWriter output) { output.Write(Text); } Also notice that the RenderContents method has one method parameter called output . This parameter is an HtmlTextWriter class, which is what the control uses to render HTML to the client. This special writer class is specifically designed to emit HTML 4.0–compliant HTML to the browser. The HtmlTex- twriter class has a number of methods you can use to emit your HTML, including RenderBeginTag and WriteBeginTag . Listing 26-13 shows how you can modify the control’s Render method to emit an HTML < input > tag. Listing 26-13: Using the HtmlTextWriter to render an HTML tag VB Protected Overrides Sub RenderContents(ByVal output As HtmlTextWriter) output.RenderBeginTag(HtmlTextWriterTag.Input) output.RenderEndTag() End Sub C# protected override void RenderContents(HtmlTextWriter output) { output.RenderBeginTag(HtmlTextWriterTag.Input); output.RenderEndTag(); } 1212 Evjen c26.tex V2 - 01/28/2008 3:48pm Page 1213 Chapter 26: User and Server Controls FrameworkInitialize AddParsedSubObject CreateControlCollection AddedControl Loop to add all controls resident on the page AddParsedSubObject DeterminePostBakMode PreInit Init TrackViewState InitComplete LoadPageFromPersistanceMedium PreLoad Load RaisePostbackEvent LoadComplete PreRenderComplete PreRender SaveViewState SavePageToPersistanceMedium SaveStateComplete RenderControl VerifyRenderingServerForm Unload Figure 26-6 First, notice that the RenderBeginTag method is used to emit the HTML. The advantage of using this method to emit HTML is that it requires you to select a tag from the HtmlTextWriterTag enumera- tion. Using the RenderBeginTag method and the HtmlTextWriterTag enumeration enables you to have your control automatically support downlevel browsers that cannot understand HTML 4.0 syntax. If a downlevel browser is detected by ASP.NET, the control automatically emits HTML 3.2 syntax instead of HTML 4.0. 1213 Evjen c26.tex V2 - 01/28/2008 3:48pm Page 1214 Chapter 26: User and Server Controls Second, notice that the RenderEndTag method is also used. As the name suggests, this method renders the closing tag. Notice, however, that you do not have to specify in this method which tag you want to close. The RenderEndTag automatically closes the last begin tag rendered by the RenderBeginTag method, whichinthiscaseisthe < input > tag. If you want to emit multiple HTML tags, make sure you order your Begin and End render methods properly. In Listing 26-14, for example, you add a < div > tag to the control. The < div > tag surrounds the < input > tag when rendered to the page. Listing 26-14: Using the HtmlTextWriter to render multiple HTML tags VB Protected Overrides Sub RenderContents(ByVal output As HtmlTextWriter) output.RenderBeginTag(HtmlTextWriterTag.Div) output.RenderBeginTag(HtmlTextWriterTag.Input) output.RenderEndTag() output.RenderEndTag() End Sub C# protected override void RenderContents(HtmlTextWriter output) { output.RenderBeginTag(HtmlTextWriterTag.Div); output.RenderBeginTag(HtmlTextWriterTag.Input); output.RenderEndTag(); output.RenderEndTag(); } Now that you have a basic understanding of how to emit simple HTML, look at the output of your control. You can do this by viewing the test HTML page containing the control in a browser and choosing View ➪ Source. Figure 26-7 shows the source for the page. You can see that the control emitted some pretty simple HTML markup. Also notice (in the highlighted area) that the control was smart enough to realize that the input control did not contain any child controls and, therefore, the control did not need to render a full closing tag. Instead, it automatically rendered the shorthand / > , rather than < /input >. Adding Tag Attributes Emitting HTML tags is a good start to building the control, but perhaps this is a bit simplistic. Normally, when rendering HTML you would emit some tag attributes (such as ID or Name ) to the client in addition to the tag. Listing 26-15 shows how you can easily add tag attributes. Listing 26-15: Rendering HTML tag attributes VB Protected Overrides Sub RenderContents(ByVal output As HtmlTextWriter) output.RenderBeginTag(HtmlTextWriterTag.Div) output.AddAttribute(HtmlTextWriterAttribute.Type, "text") output.AddAttribute(HtmlTextWriterAttribute.Id, Me.ClientID & "_i") output.AddAttribute(HtmlTextWriterAttribute.Name, Me.ClientID & "_i") output.AddAttribute(HtmlTextWriterAttribute.Value, Me.Text) 1214 Evjen c26.tex V2 - 01/28/2008 3:48pm Page 1215 Chapter 26: User and Server Controls output.RenderBeginTag(HtmlTextWriterTag.Input) output.RenderEndTag() output.RenderEndTag() End Sub C# protected override void RenderContents(HtmlTextWriter output) { output.RenderBeginTag(HtmlTextWriterTag.Div); output.AddAttribute(HtmlTextWriterAttribute.Type, "text"); output.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID + "_i"); output.AddAttribute(HtmlTextWriterAttribute.Name, this.ClientID + "_i"); output.AddAttribute(HtmlTextWriterAttribute.Value, this.Text); output.RenderBeginTag(HtmlTextWriterTag.Input); output.RenderEndTag(); output.RenderEndTag(); } Figure 26-7 1215 Evjen c26.tex V2 - 01/28/2008 3:48pm Page 1216 Chapter 26: User and Server Controls You can see that by using the AddAttribute method, you have added three attributes to the < input > tag. Also notice that, once again, you are using an enumeration, HtmlTextWriterAttribute , to select the attribute you want to add to the tag. This serves the same purpose as using the HtmlTextWriterTag enumeration, allowing the control to degrade its output to downlevel browsers. As with the Render methods, the order in which you place the AddAttributes methods is important. You place the AddAttributes methods directly before the RenderBeginTag method in the code. The AddAttributes method associates the attributes with the next HTML tag that is rendered by the Render- BeginTag method — in this case the < input > tag. Now browse to the test page and check out the HTML source with the added tag attributes. Figure 26-8 shows the HTML source rendered by the control. Figure 26-8 You can see that the tag attributes you added in the server control are now included as part of the HTML tag rendered by the control. 1216 Evjen c26.tex V2 - 01/28/2008 3:48pm Page 1217 Chapter 26: User and Server Controls A Word about Control IDs Notice that in Listing 26-11 it’s important to use the control’s ClientID property as the value of both the Id and Name attributes. Controls that derive from the WebControl class automatically expose three different types of ID properties: ID , UniqueID ,and ClientID . Each of these properties exposes a slightly altered version of the control’s ID for use in a specific scenario. The ID property is the most obvious. Developers use it to get and set the control’s ID. It must be unique to the page at design time. The UniqueID property is a read-only property generated at runtime that returns an ID that has been prepended with the containing control’s ID. This is essential so that ASP.NET can uniquely identify each control in the page’s control tree, even if the con- trol is used multiple times by a container control such as a Repeater or GridView. For example, if you add this custom control to a repeater, the UniqueID for each custom control rendered by the Repeater is modified to include the Repeater’s ID when the page executed: MyRepeater:Ctrl0:MyCustomControl The ClientID property is essentially identical to the UniqueID property with one important exception. The ClientID property always uses an underscore ( )tosep- arate the ID values, rather than using the value of the IdSeparator property. This is because the ECMAScript standard disallows the use of colons in ID attribute values, which is the default value of the IdSeparator property. Using the underscore ensures that a control can be used by client-side JavaScript. Additionally, in order to ensure that controls can generate a unique ID, they should implement the INamingContainer interface. This is a marker interface only, meaning that it does not require any additional methods to be implemented; it does, however, ensure that the ASP.NET runtime guarantees the control always has a unique name within the page’s tree hierarchy, regardless of its container. Styling HTML So far, you have seen how easy it is to build a simple HTML control and emit the proper HTML, including attributes. In this section, we discuss how you can have your control render style informa- tion. As mentioned at the very beginning of this section, you are creating controls that inherit from the WebControl class. Because of this, these controls already have the basic infrastructure for emitting most of the standard CSS-style attributes. In the Property Browser for this control, you should see a num- ber of style properties already listed, such as background color, border width, and font. You can also launch the style builder to create complex CSS styles. These basic properties are provided by the WebCon- trol class, but it is up to you to tell your control to render the values set at design time. To do this, you simply execute the AddAttributesToRender method. Listing 26-16 shows you how to do this. 1217 Evjen c26.tex V2 - 01/28/2008 3:48pm Page 1218 Chapter 26: User and Server Controls Listing 26-16: Rendering style properties VB Protected Overrides Sub RenderContents(ByVal output As HtmlTextWriter) output.RenderBeginTag(HtmlTextWriterTag.Div) output.AddAttribute(HtmlTextWriterAttribute.Type, "text") output.AddAttribute(HtmlTextWriterAttribute.Id, Me.ClientID & "_i") output.AddAttribute(HtmlTextWriterAttribute.Name, Me.ClientID & "_i") output.AddAttribute(HtmlTextWriterAttribute.Value, Me.Text) Me.AddAttributesToRender(output) output.RenderBeginTag(HtmlTextWriterTag.Input) output.RenderEndTag() output.RenderEndTag() End Sub C# protected override void RenderContents(HtmlTextWriter output) { output.RenderBeginTag(HtmlTextWriterTag.Div); output.AddAttribute(HtmlTextWriterAttribute.Type, "text"); output.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID + "_i"); output.AddAttribute(HtmlTextWriterAttribute.Name, this.ClientID + "_i"); output.AddAttribute(HtmlTextWriterAttribute.Value, this.Text); this.AddAttributesToRender(output); output.RenderBeginTag(HtmlTextWriterTag.Input); output.RenderEndTag(); output.RenderEndTag(); } Executing this method tells the control to render any style information that has been set. Note that executing this method not only causes the style-related properties to be rendered, but also several other attributes, including ID , tabindex ,and tooltip . If you are manually rendering these attributes earlier in your control, then you may end up with duplicate attributes being rendered. Addi- tionally, be careful about where you use the AddAttributesToRender method. In Listing 26-26, it is executed immediately before the Input tag is rendered, which means that the attributes will be rendered both on the Input element and on the Span element surrounding the Input element. Try placing the method call before the beginning DIV tag is rendered, or after the DIV’s end tag is rendered. You will see that in the case of the former, the attributes are now applied to the DIV and its surrounding span and in the case of the latter, only the SPAN has the attribute applied. Using the Property Browser, you can set the background color of the control to Red and the font to Bold . When you set these properties, they are automatically added to the control tag in the ASP.NET page. After you have added the styles, the control tag looks like this: < cc1:ServerControl1 BackColor="Red" Font-Bold=true ID="ServerControl11" runat="server" /> 1218 Evjen c26.tex V2 - 01/28/2008 3:48pm Page 1219 Chapter 26: User and Server Controls The style changes have been persisted to the control as attributes. When you execute this page in the browser, the style information should be rendered to the HTML, making the background of the text box red and its font bold. Figure 26-9 shows the page in the browser. Figure 26-9 Once again, look at the source for this page. The style information has been rendered to the HTML as a style tag. Figure 26-10 shows the HTML emitted by the control. Figure 26-10 1219 Evjen c26.tex V2 - 01/28/2008 3:48pm Page 1220 Chapter 26: User and Server Controls If you want more control over the rendering of styles in your control you can use the HtmlTextWriters AddStyleAttribute method. Similar to the AddAttribute method, the AddStyleAttribute method enables you to specify CSS attributes to add to a control using the HtmlTextWriterStyle enumeration. However, unlike the AddAttribute method, attributes added using AddStyleAttribute are defined inside of a style attribute on the control. Listing 26-17 demonstrates the use of the AddStyleAttribute method. Listing 26-17: Adding control styes using AddStyleAttribute VB Protected Overrides Sub RenderContents(ByVal output As HtmlTextWriter) output.RenderBeginTag(HtmlTextWriterTag.Div) output.AddAttribute(HtmlTextWriterAttribute.Type, "text") output.AddAttribute(HtmlTextWriterAttribute.Id, Me.ClientID & "_i") output.AddAttribute(HtmlTextWriterAttribute.Name, Me.ClientID & "_i") output.AddAttribute(HtmlTextWriterAttribute.Value, Me.Text) output.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, "Red") output.RenderBeginTag(HtmlTextWriterTag.Input) output.RenderEndTag() output.RenderEndTag() End Sub C# protected override void RenderContents(HtmlTextWriter output) { output.RenderBeginTag(HtmlTextWriterTag.Div); output.AddAttribute(HtmlTextWriterAttribute.Type, "text"); output.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID + "_i"); output.AddAttribute(HtmlTextWriterAttribute.Name, this.ClientID + "_i"); output.AddAttribute(HtmlTextWriterAttribute.Value, this.Text); output.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, "Red"); output.RenderBeginTag(HtmlTextWriterTag.Input); output.RenderEndTag(); output.RenderEndTag(); } Running this sample will result in the same red background color being applied to the control. Themes and Skins A great feature added in ASP.NET 2.0, and introduced to you in Chapter 6, is themes and skins. This feature allows you to create visual styles for your Web applications. In this section, you learn what you need to know about themes and skins when creating a server control. As you saw in Chapter 6, skins are essentially a way to set default values for the UI elements of controls in your Web application. You simply define the control and its properties in a .skin file and the values are applied to the control at runtime. Listing 26-18 shows a sample skin. 1220 . emit your HTML, including RenderBeginTag and WriteBeginTag . Listing 26- 13 shows how you can modify the control’s Render method to emit an HTML < input > tag. Listing 26- 13: Using the HtmlTextWriter. Skins A great feature added in ASP. NET 2.0, and introduced to you in Chapter 6, is themes and skins. This feature allows you to create visual styles for your Web applications. In this section, you learn. as nested inner controls PersistanceMode Specifies how a property or an event is persisted to the ASP. NET page TemplateContainer Specifies the type of INamingContainer that will contain the template