1. Introduction
In the previous task, we added the data binding feature for the star control, but there will be more requirements in practical use. For example, you may want to create a course list (1):
You can also manually control the data arrangement when there are many data items (figure 2)
In this task, we will develop such controls together.
2. Analysis
The preceding two legends show a list control. in NET2.0, The ListControl class is the parent class of the list control. Through the analysis of the previous task, we can understand that the CheckBoxList, RadioButtonList, DropDownList, and other controls are inherited from the ListControl class, these list controls apply a style for each data item repeatedly. For example, CheckBoxList displays a check box for each list item, while RadioButtonList displays a cell box for each list item. In fact, each list item in the list control is of the ListItem type. to display a list, the list control often has a set of ListItem elements, which are commonly used Items attributes, this attribute is defined on the ListControl class. The ListControl class also has many other useful attributes:
Attribute |
Description |
AppendDataBoundItems |
Gets or sets a value to indicate whether to clear the list items before binding data. |
DataTextField |
Obtain or set the data source field that provides text content for the list item |
DataTextFormatString |
Gets or sets a formatted string that controls how data bound to the list control is displayed. |
DataValueField |
Obtain or set the data source fields that provide values for each list item |
SelectedIndex |
Obtains or sets the index of the lowest serial number of the selected item in the list. |
SelectedItem |
Obtains the minimum selected index in the list control. |
SelectedValue |
Obtains the value of a selected item in the list control, or selects an item that contains a specified value in the list control. |
In the above attributes, the AppendDataBoundItems attribute is added in. NET2.0. This attribute is particularly useful when you manually define certain items in the list before executing data binding. For example, in the drop-down list, you may want to add a "please select" project for the user, you can use the <asp: ListItem/> tag to define this list item, and set the AppendDataBoundItems attribute to true, when the data binding operation is performed again in the drop-down list, the select project is retained.
For the first requirement of this task, you only need to inherit from the ListControl class and output each data item as a hyperlink during rendering. However, this list control has some limitations. It can only use the ListItem class as the data item object type. If you want to modify or add the list item attribute, this list control is powerless, to achieve this purpose (for example, the second requirement), some additional work is required.
Next, consider the second requirement. You need to add the ability to present data items in the specified direction for the custom control based on data binding. This is a bit like the DataList control, you can set attributes such as RepeatDirection and RepeatColumns to implement the above functions. For this type of problem,. NET provides the IRepeatInfoUser interface, which contains the declaration of the following members:
Attribute |
Description |
HasFooter attributes |
Gets a value indicating whether the list control contains a footer. |
HasHeader attributes |
Gets a value indicating whether the list control contains the TITLE section. |
HasSeparators attributes |
Gets a value that indicates whether the list control contains a delimiter between list items. |
RepeatedItemCount attribute |
Obtain the number of items in the list control. |
GetItemStyle Method |
Retrieve the style of the specified item type at the specified index position in the list control. |
RenderItem |
Displays items in the list with the specified information |
To implement new features and enable custom controls to implement the IRepeatInfoUser interface, it is important that the RenderItem method in this interface is automatically called for each bound data item. The signature of this method is as follows:
void RenderItem ( ListItemType itemType, int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer)
The parameters are described as follows:
Parameters |
Description |
ItemType |
One of the ListItemType enumerated values, which specifies the type of items in the list control. |
RepeatIndex |
Specifies the serial number index of the position of the item in the list control. |
RepeatInfo |
RepeatInfo type object, used to display the information of items in the list |
Writer |
System. Web. UI. HtmlTextWriter class instance, indicating the output stream used to render HTML content on the client |
Finally, if the control wants to support special layout functions, you also need to use special code to override the Render method of the custom control. In this method, use the RenderPrpeater method of the RepeatInfo class to Render the control, the following is the definition of this method:
public void RenderRepeater ( HtmlTextWriter writer, IRepeatInfoUser user, Style controlStyle, WebControl baseControl)
The parameters are described as follows:
Parameters |
Description |
Writer |
System. Web. UI. HtmlTextWriter class instance, indicating the output stream used to render HTML content on the client |
User |
An object that implements the IRepeatInfoUser interface, indicating the control to be rendered |
ControlStyle |
Indicates the style used by the display item. |
BaseControl |
Copy the control of the base attribute |
Based on the above analysis, write two custom controls to output data items.
3. implement simple list controls
3.1 create the SimpleHyperLinkList class in the ControlLibrary class library of the solution and introduce the necessary namespace:
using System.Web.UI;using System.Web.UI.WebControls; namespace ControlLibrary{ [ToolboxData("<{0}:SimpleHyperLinkList runat=\"server\"></{0}>")] public class SimpleHyperLinkList : ListControl { }}
3.2 override the Render method of the Control. When rendering, iterate the access data item to present multiple linked controls. The RenderControl method is called here, which is defined on the Control class, it is used to input the content of the server control to the provided HtmlTextWriter object:
protected override void Render(HtmlTextWriter writer){ HyperLink link = new HyperLink(); for (int i = 0; i < Items.Count; i++) { link.ApplyStyle(ControlStyle); link.Text = Items[i].Text; link.NavigateUrl = Items[i].Value; link.RenderControl(writer); writer.Write("<br />"); }}
The code for this class is very simple. the only interesting thing is that the class uses the ToolboxData feature (corresponding to System. web. UI. toolboxDataAttribute class), which specifies the tag generated by default when the control is dragged from the toolbox of the visualization designer to the design page, this feature is useful when you need to specify an attribute initial value for a custom control.
3.3 declare and define controls on the ASPX page to view running results.
4. Implement rich feature list controls
4.1 create a HyperLinkItem entity class in the ControlLibrary class library to save the text, comments, and address strings of each generated link:
namespace ControlLibrary{ public class HyperLinkItem { public HyperLinkItem() { Text = string.Empty; Tooltip = string.Empty; Url = string.Empty; } public HyperLinkItem(string text, string tooltip, string url) { Text = text; Tooltip = tooltip; Url = url; } public string Text { get; set; } public string Tooltip { get; set; } public string Url { get; set; } }}
4.2 create a HyperLinkItemCollection class in the class library, which inherits the Collection generic Collection class to ensure that only HyperLinkItem type objects are added to the set, and to manually manage the view status, this class implements the IStateManager interface:
using System.Collections.ObjectModel;using System.Web.UI; namespace ControlLibrary{ public class HyperLinkItemCollection:Collection<HyperLinkItem>,IStateManager { private bool marked; public HyperLinkItemCollection() { marked = false; } public bool IsTrackingViewState { get { return this.marked; } } public void TrackViewState() { marked = true; } public void LoadViewState(object state) { if (state == null) return; Clear(); Triplet trip = (Triplet)state; string[] rgTooltip = (string[])trip.First; string[] rgText = (string[])trip.Second; string[] rgUrl = (string[])trip.Third; for (int i = 0; i < rgUrl.Length; i++) { Add(new HyperLinkItem(rgText[i], rgTooltip[i], rgUrl[i])); } } public object SaveViewState() { int num = Count; object[] rgTooltip = new string[num]; object[] rgText = new string[num]; object[] rgUrl = new string[num]; for (int i = 0; i < num; i++) { rgTooltip[i] = Items[i].Tooltip; rgText[i] = Items[i].Text; rgUrl[i] = Items[i].Url; } return new Triplet(rgTooltip, rgText, rgUrl); } }}
The code above is a little complicated because the view State is saved and read. To ensure that all three attributes of a HyperLinkItem are saved to the view state, three object arrays are defined and finally saved to the Triplet object (this rule is still observed during reading ).
4.3 Add the HyperLinkList class to the class library. In order to make the class more informative, it still inherits from the DataBindControl class and implements the IRepeatInfoUser interface:
using System.Collections;using System.Web.UI;using System.Web.UI.WebControls; namespace ControlLibrary{ [ToolboxData("<{0}:HyperLinkList runat=\"server\"></{0}>")] public class HyperLinkList:DataBoundControl,IRepeatInfoUser { }}
4.4 define the repeated item attributes and exposed set attributes used inside the control. Write the following code in the HyperLinkList class:
private HyperLinkItemCollection items;private HyperLink controlToRepeat; private HyperLink ControlToRepeat{ get { if (controlToRepeat == null) { controlToRepeat = new HyperLink(); } return controlToRepeat; }} public virtual HyperLinkItemCollection Items{ get { if (items == null) items = new HyperLinkItemCollection(); if (base.IsTrackingViewState) items.TrackViewState(); return items; }}
4.5 define the data source ing attributes DataTextField, DataValueField, and DataTooltipField to read the corresponding data fill repeated items from the Data source:
public virtual string DataTextField{ get { object o = ViewState["DataTextField"]; return o == null ? string.Empty : (string)o; } set { ViewState["DataTextField"] = value; }} public virtual string DataTooltipField{ get { object o = ViewState["DataTooltipField"]; return o == null ? string.Empty : (string)o; } set { ViewState["DataTooltipField"] = value; }} public virtual string DataUrlField{ get { object o = ViewState["DataUrlField"]; return o == null ? string.Empty : (string)o; } set { ViewState["DataUrlField"] = value; }}
4.6 rewrite the PerformDataBinding method to read data from the data source based on the ing:
protected override void PerformDataBinding(IEnumerable data){ base.PerformDataBinding(data); string urlField = DataUrlField; string textField = DataTextField; string tooltipField = DataTooltipField; if (data != null) { foreach (object o in data) { HyperLinkItem item = new HyperLinkItem(); item.Url = DataBinder.GetPropertyValue(o, DataUrlField,null); item.Text = DataBinder.GetPropertyValue(o, DataTextField,null); item.Tooltip = DataBinder.GetPropertyValue(o, DataTooltipField,null); Items.Add(item); } }}
4.7 rewrite the SaveViewState and LoadViewState methods to save or read the data item set:
protected override object SaveViewState(){ object o= base.SaveViewState(); Pair p = new Pair(o, Items.SaveViewState()); return p;} protected override void LoadViewState(object savedState){ if (savedState==null) return; Pair p = (Pair)savedState; base.LoadViewState(p.First); Items.LoadViewState(p.Second);}
4.8 define RepeatDirection, RepeatColumns, and RepeatLayout attributes for RepeatInfo objects to control the presentation of repeated items:
public virtual RepeatDirection RepeatDirection{ get { object o = ViewState["RepeatDirection"]; return o == null ? RepeatDirection.Vertical : (RepeatDirection)o; } set { ViewState["RepeatDirection"] = value; }} public virtual int RepeatColumns{ get { object o = ViewState["RepeatColumns"]; return o == null ? 0 : (int)o; } set { ViewState["RepeatColumns"] = value; }} public virtual RepeatLayout RepeatLayout{ get { object o = ViewState["RepeatLayout"]; return o == null ? 0 : (RepeatLayout)o; } set { ViewState["RepeatLayout"] = value; }}
4.9 implement members of the IRepeatInfoUser interface. For convenience, no new features are added:
bool IRepeatInfoUser.HasFooter{ get { return false; }} bool IRepeatInfoUser.HasHeader{ get { return false; }} bool IRepeatInfoUser.HasSeparators{ get { return false; }} Style IRepeatInfoUser.GetItemStyle(ListItemType type, int repeatIndex){ return null;}
4.10 implement the RepeatedItemCount attribute of the IRepeatInfoUser interface and return the current number of output items:
int IRepeatInfoUser.RepeatedItemCount{ get { return this.Items.Count; }}
4.11 implement the RenderItem method of the IRepeatInfoUser interface to present data items. This method calls the ControlToRepeat private attribute to get a hyperlink:
void IRepeatInfoUser.RenderItem(ListItemType type, int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer){ HyperLink link = ControlToRepeat; int i = repeatIndex; link.ID = i.ToString(); link.Text = Items[i].Text; link.NavigateUrl = Items[i].Url; link.ToolTip = Items[i].Tooltip; link.RenderControl(writer);}
4.12 rewrite the Render method to Render the control. According to the analysis, the RepeatInfo class is used here:
protected override void Render(HtmlTextWriter writer){ if (Items.Count > 0) { RepeatInfo ri = new RepeatInfo(); Style controlStyle = base.ControlStyleCreated ? base.ControlStyle : null; ri.RepeatColumns = RepeatColumns; ri.RepeatDirection = RepeatDirection; ri.RepeatLayout = RepeatLayout; ri.RenderRepeater(writer, this, controlStyle, this); }}
4.13 create a test ASPX page, declare and define custom controls, and preview the running results.
5. Summary
In this task, we wrote a simple list control inherited from the ListControl class. On this basis, we developed a new class inherited from DataBindControl, and in order to implement rich layout functions, the IRepeatInfoUser class is also implemented. In the rendering method, data items are input using the RepeatInfo class according to the definition format. In the next task, we will start a slightly complex combined data binding control that looks similar to the GridView to display a list of star scores.
ASP. NET Custom Controls
Preface
Simple star control on the first day
Star controls with custom styles the next day
On the third day, use the star widget in the control status.
Fold panel custom controls on the fourth day
Star controls that can be scored on the fifth day
Star controls that can be bound to data sources on the sixth day
Develop list controls with rich features on the seventh day
Metric days: displays the data binding controls for multiple entry star rating
The ninth day custom GridView
DataList that implements the paging function on the tenth day
Download all source code
Download this series of articles in PDF