Implementation of typed style attributes
Classes inherited from the Style class are called typed styles. The Style class can be extended by the control developer to create a custom typed Style, which overwrites or adds the attributes of the Style class. The server control can also use a custom style as the type of the ControlStyle attribute. For example, the ControlStyle attribute of the Table control is of the TableStyle type, which is an extended Style. attributes such as CellPadding, CellSpacing, and GridLines are added. After a preliminary understanding of the basic concepts of typed style attributes, the following lists the key points of implementation methods for typed style attributes.
(1) create a class derived from System. Web. UI. WebControls. Style;
(2) define the properties that the style will provide for the control. Save this attribute in the ViewState Dictionary of the Style;
(3) rewrite the CopyFrom and MergeWith methods to copy or merge the defined attributes from the defined attributes and the attributes of a given style;
(4) override the Reset method and delete the attributes added to ViewState;
(5) rewrite the AddAttributesToRender method to generate HTML and CSS features as part of the control rendering process.
In fact, creating a typed style attribute is not a simple process. To this end, we will use typical application examples to describe the specific creation methods so that readers can better understand the implementation points.
Typical applications
This section describes how to implement and use custom typed styles by creating a MyPanel control and an associated typed style MyPanelStyle. In terms of functionality, the built-in Panel controls of MyPanel and ASP. NET 2.0 are the same. Developers can add Controls to the Controls set by embedding the Controls in the control label. In the visualization designer, drag and drop the control to be added to the Panel design interface to add the control to the Controls set. However, MyPanel does not inherit from the Panel class but is the result of custom implementation. At the same time, the control also provides the typed style attribute MyPanelStyle, where three style attributes are set:
(1) BackImageUrl, used to specify the URL of the background image;
(2) HorizontalAlign, used to specify the horizontal method of the added content;
(3) Wrap, used to specify whether to allow line breaks to the added content.
The following is an example.
Figure 1
1. The figure shows a MyPanel control, which contains a line of text. The background image of the text has been defined and the text is in the center.
The following lists the source code of MyPanel. cs that implements custom server controls.
Using System;
Using System. Collections. Generic;
Using System. ComponentModel;
Using System. Text;
Using System. Web;
Using System. Web. UI;
Using System. Web. UI. WebControls;
Namespace WebControlLibrary {
[ParseChildren (false), PersistChildren (true)]
[ToolboxData ("<{0}: MyPanel runat = server> </{0}: MyPanel>")]
Public class MyPanel: WebControl {
// Define the constructor
Public MyPanel (): base (HtmlTextWriterTag. Div ){}
// Implement the BackImageUrl attribute
[Bindable (true)] [Category ("Appearance")]
[DefaultValue ("")]
Public virtual string BackImageUrl {
Get {
If (ControlStyleCreated ){
Return (MyPanelStyle) ControlStyle). BackImageUrl;
}
Return String. Empty;
}
Set {
(MyPanelStyle) ControlStyle). BackImageUrl = value;
}
}
// Implement the HorizontalAlign attribute
[Bindable (true)]
[Category ("Layout")]
[DefaultValue ("")]
Public virtual HorizontalAlign {
Get {
If (ControlStyleCreated ){
Return (MyPanelStyle) ControlStyle). HorizonalAlign;
}
Return HorizontalAlign. NotSet;
}
Set {
(MyPanelStyle) ControlStyle). HorizonalAlign = value;
}
}
// Implement the Wrap attribute
[Bindable (true)]
[Category ("Layout")]
[DefaultValue ("")]
Public virtual bool Wrap {
Get {
If (ControlStyleCreated ){
Return (MyPanelStyle) ControlStyle). Wrap;
}
Return true;
}
Set {
(MyPanelStyle) ControlStyle). Wrap = value;
}
}
Protected override Style CreateControlStyle (){
Return new MyPanelStyle (ViewState );
}
}
}
Before the analysis, in order to help readers better read the above source code, the following lists the MyPanel class diagrams.
Figure 2
As shown in the above Code, MyPanel inherits from the WebControl base class and defines three attributes: BackImageUrl, HorizontalAlign, and Wrap. For more information about these three attributes, see the previous section. In addition, MyPanel overrides the CreateControlStyle method and returns a MyPanelStyle object. In this way, the returned MyPanelStyle instance is indirectly assigned the ControlStyle attribute. The reason for this implementation is that the ControlStyle attribute is a read-only attribute, and its access operations need to call the CreateControlStyle method time to set. Note that CreateControlStyle passes the ViewState of the MyPanel control to the constructor of MyPanelStyle. When creating a new Style for the control in CreateControlStyle, you must pass the ViewState of the control to the Style constructor. Then, the Style object uses the same StateBag as the control.
The following lists the source code for implementing the MyPanelStyle class, which comes from the MyPanelStyle. cs file.
Using System;
Using System. Collections. Generic;
Using System. ComponentModel;
Using System. Text;
Using System. Web;
Using System. Web. UI;
Using System. Web. UI. WebControls;
Namespace WebControlLibrary {
Public class MyPanelStyle: Style {
// Define internal Constants
Internal const int PROP_BACKIMAGEURL = 1;
Internal const int PROP_HORIZONTALALIGN = 2;
Internal const int PROP_WRAP = 3;
// Constructor 1
Public MyPanelStyle (){}
// Constructor 2
Public MyPanelStyle (StateBag bag): base (bag ){}
// Create BackImageUrl attributes
[Bindable (true), Category ("Appearance"), DefaultValue (""), Description ("URL of the background image"), policyparentproperty (true)]
Public virtual string BackImageUrl {
Get {
If (IsSet (PROP_BACKIMAGEURL )){
Return (string) ViewState ["BackImageUrl"];
}
Return String. Empty;
}
Set {
ViewState ["BackImageUrl"] = value;
}
}
// Implement the HorizonalAlign attribute
[Bindable (true), Category ("Layout"), DefaultValue (HorizontalAlign. NotSet), Description ("method of adding content horizontally"), policyparentproperty (true)]
Public virtual HorizontalAlign HorizonalAlign {
Get {
If (IsSet (PROP_HORIZONTALALIGN )){
Return (HorizontalAlign) ViewState ["HorizontalAlign"];
}
Return HorizontalAlign. NotSet;
}
Set {
If (value <HorizontalAlign. NotSet | value> HorizontalAlign. Justify ){
Throw new ArgumentOutOfRangeException ("value ");
}
ViewState ["HorizontalAlign"] = value;
}
}
// Implement IsEmpty
Protected new internal bool IsEmpty {
Get {
Return base. IsEmpty &&! IsSet (PROP_BACKIMAGEURL )&&! IsSet (PROP_HORIZONTALALIGN )&&! IsSet (PROP_WRAP );
}
}
// Implement the Wrap attribute
[Bindable (true), Category ("Layout"), DefaultValue (true), Description ("whether to allow line breaks to added content"), policyparentproperty (true)]
Public virtual bool Wrap {
Get {
If (IsSet (PROP_WRAP) {return (bool) ViewState ["Wrap"];}
Return true;
}
Set {ViewState ["Wrap"] = value ;}
}
// Auxiliary method IsSet
Internal bool IsSet (int propNumber ){
String key = null;
Switch (propNumber ){
Case PROP_BACKIMAGEURL: key = "BackImageUrl ";
Break;
Case PROP_HORIZONTALALIGN: key = "HorizontalAlign ";
Break;
Case PROP_WRAP: key = "Wrap ";
Break;
}
If (key! = Null ){
Return ViewState [key]! = Null;
}
Return false;
}
// Override the AddAttributesToRender Method
Public override void AddAttributesToRender (HtmlTextWriter writer, WebControl owner ){
If (IsSet (PROP_BACKIMAGEURL )){
String s = BackImageUrl;
If (s. Length> 0 ){
If (owner! = Null ){
S = owner. ResolveUrl (s );
}
Writer. AddStyleAttribute (HtmlTextWriterStyle. BackgroundImage, "url (" + s + ")");
}
}
If (IsSet (PROP_HORIZONTALALIGN )){
System. Web. UI. WebControls. HorizontalAlign hAlign = this. HorizonalAlign;
If (hAlign! = System. Web. UI. WebControls. HorizontalAlign. NotSet ){
TypeConverter hac = TypeDescriptor. GetConverter (typeof (HorizontalAlign ));
Writer. addattriign (HtmlTextWriterAttribute. Align, hac. ConvertToInvariantString (hAlign ));
}
}
If (IsSet (PROP_WRAP )){
Bool wrap = Wrap;
If (! Wrap ){
Writer. AddAttribute (HtmlTextWriterAttribute. Nowrap, "nowwrap ");
}
}
Base. AddAttributesToRender (writer, owner );
}
// Rewrite the CopyFrom Method
Public override void CopyFrom (Style s ){
If (s! = Null ){
Base. CopyFrom (s );
If (s is MyPanelStyle ){
MyPanelStyle mps = (MyPanelStyle) s;
If (! Mps. IsEmpty ){
If (mps. IsSet (PROP_BACKIMAGEURL ))
This. BackImageUrl = mps. BackImageUrl;
If (mps. IsSet (PROP_HORIZONTALALIGN ))
This. HorizonalAlign = mps. HorizonalAlign;
If (mps. IsSet (PROP_WRAP ))
This. Wrap = mps. Wrap;
}
}
}
}
// Override the MergeWith Method
Public override void MergeWith (Style s ){
If (s! = Null ){
If (IsEmpty ){
CopyFrom (s );
Return;
}
Base. MergeWith (s );
If (s is MyPanelStyle ){
MyPanelStyle mps = (MyPanelStyle) s;
If (! Mps. IsEmpty ){
If (mps. IsSet (PROP_BACKIMAGEURL )&&! This. IsSet (PROP_BACKIMAGEURL ))
This. BackImageUrl = mps. BackImageUrl;
If (mps. IsSet (PROP_HORIZONTALALIGN )&&! This. IsSet (PROP_HORIZONTALALIGN ))
This. HorizonalAlign = mps. HorizonalAlign;
If (mps. IsSet (PROP_WRAP )&&! This. IsSet (PROP_WRAP ))
This. Wrap = mps. Wrap;
}
}
}
}
// Rewrite the Reset method
Public override void Reset (){
Base. Reset ();
If (IsEmpty) return;
If (IsSet (PROP_BACKIMAGEURL ))
ViewState. Remove ("BackImageUrl ");
If (IsSet (PROP_HORIZONTALALIGN ))
ViewState. Remove ("HorizontalAlign ");
If (IsSet (PROP_WRAP) ViewState. Remove ("Wrap ");
}
}
}
The following lists the MyPanelStyle class diagrams.
Figure 3
Some readers may feel that the implementation of the MyPanelStyle class is somewhat complicated. However, it is still traceable. The implementation of this class is strictly in accordance with the aforementioned method for creating typed style attributes.
First, the MyPanelStyle class inherits the Style class, which is the key to creating typed Style attributes. Then, three attributes BackImageUrl, HorizontalAlign, and Wrap are defined. These three attributes support the style attributes in MyPanel. The Code then overwrites the AddAttributesToRender method to accurately generate the relevant HTML and CSS code when the control is rendered. Note that the second parameter of this method cannot be blank, which indicates that it has a specific control of the Style object. Finally, three methods from the Style are rewritten in the Code: CopyFrom, MergeWith, and Reset. The first two methods of rewriting are to copy the given MyPanelStyle or merge the given MyPanelStyle with itself. Both methods call the base class method and then execute their own logic. The Reset method is rewritten to delete the attributes added to ViewState. Its implementation logic is similar to that of the first two methods. It calls the base class method and then executes its own logic.
The following lists the source code of the Default. aspx file created to test the MyPanel control.
<% @ Page Language = "C #" AutoEventWireup = "true" CodeFile = "Default. aspx. cs" Inherits = "_ Default" %>
<% @ Register TagPrefix = "wcl" Assembly = "WebControlLibrary" Namespace = "WebControlLibrary" %>
<! DOCTYPE html PUBLIC "-// W3C // dtd xhtml 1.0 Transitional // EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<Html xmlns = "http://www.w3.org/1999/xhtml">
<Head runat = "server">
<Title> typed style attributes </title>
</Head>
<Body>
<Form id = "form1" runat = "server">
<Wcl: MyPanel ID = "demo1" runat = "server" BackImageUrl = "pic1.jpg" HorizontalAlign = "Center" Height = "145" Width = "160">
<Br/>
<Br/>
This is a line of text in the MyPanel control.
</Wcl: MyPanel>
</Form>
</Body>
</Html>
As shown in the code above, developers can set the control to be added to the MyPanel label just like using the Panel control. In this way, the configured control is automatically displayed, and the display appearance and style change due to the property settings of the MyPanel control.
Summary
This article introduces the implementation methods of typed style attributes, and uses a typical example to enhance your understanding of the implementation methods. In the following article, we will continue to discuss the use of ASP. NET 2.0 technology to implement the functions of the control client.