ASP. NET custom control displays the list controls for multiple entry star rating within one day

Source: Internet
Author: User
1. Introduction

In the previous tasks, the star control we developed can only display one score. In real life, we often encounter the need to display the scoring status of a series of data to users, as shown in:

In this task, we will develop such a control.

2. Analysis

As you can see, this custom control is a list of data rating levels. It is clear that multiple data entries can be displayed flexibly only when it is implemented as a data binding control, the title and current date are displayed at the top of the list. To allow users to flexibly define titles and second-level titles (current date), it is necessary to introduce the template concept and edit the template by the user, the template content is displayed. In this case, it seems that it is not suitable to use DataBoundControl as the base class of the custom control. Because we want to include multiple child controls in the control, which class should we choose as the base class?

Recall the class relationship diagram of the data-bound control in the task on the sixth day. One of the class CompositeDataBoundControl inherited from the DataBoudControl class is. NET Framework 2.0 is a new class used as the base class for the Data Server Control bound to the data source. The definition is as follows:

public abstract class CompositeDataBoundControl : DataBoundControl, INamingContainer

It can be seen that the INamingContainer is implemented only on the basis of inheriting the DataBoundControl class, which means that the child control contained in this class will generate a unique ID attribute.

But how does CompositeDataBoundControl implement data binding? In other words, if a page contains a complex data binding control, after a server-side control causes sending back, how can we ensure that the data binding control can be correctly filled? According to the design, ASP. the data binding control in. NET can only obtain data from the data binding, and does not cache any bound data. Therefore, you need to provide a special method to handle the send-back event.

Let's review the DataBoundControl class and analyze how the data is displayed. The PerformSelect method defined on the BaseDataBoundControl class is reloaded on the DataBoundControl class. The method is as follows:

protected override void PerformSelect(){     if (this.DataSourceID.Length == 0)     {         this.OnDataBinding(EventArgs.Empty);     }     DataSourceView data = this.GetData();     this._arguments = this.CreateDataSourceSelectArguments();     this._ignoreDataSourceViewChanged = true;     base.RequiresDataBinding = false;     this.MarkAsDataBound();     data.Select(this._arguments, new     DataSourceViewSelectCallback(this.OnDataSourceViewSelectCallback));}

The key to this method is that whether the data source is specified through the DataSource attribute or the performanceid attribute, the data is obtained through the data source view object (performanceview, after obtaining the data source view, the Select method of the object is called to obtain the enumerated data set (no matter how the data source is provided ), this method also receives multiple input parameters and callback functions.

So far, we have been able to set the data source for the control and find the data to be read through the data source view. Next we should consider, if you access this data set that can be bound to display it on the page?

The answer is that the callback function that processes the Select statement operation result in the data source view will finally call a reload-able protected method called the javasmdatabinding method, which is defined as follows:

protected internal virtual void PerformDataBinding (     IEnumerable data)

The receivmdatabinding method receives an IEnumerable object to access the returned data list. We can use this object to iteratively access the data and create the internal structure of the control as needed and finally present it to the user.

A data binding control is different from a data binding control. It does not save data to a view, but is handled by each sub-control, you cannot simply override the CreateChildControls method. NET Reflection tool to observe the implementation of this method in the CompositeDataBindControl class:

protected internal override void CreateChildControls(){     this.Controls.Clear();     object obj2 = this.ViewState["_!ItemCount"];     if ((obj2 == null) && base.RequiresDataBinding)     {         this.EnsureDataBound();     }     if ((obj2 != null) && (((int)obj2) != -1))     {         DummyDataSource dataSource = new DummyDataSource((int)obj2);         this.CreateChildControls(dataSource, false);         base.ClearChildViewState();     }}

The CreateChildControls method has two working modes: binding mode and non-binding mode.

In the binding mode, the control tree will be created normally. Specifically, the overloaded CreateChildControls method will be called in the execution of the mongomdatabinding method to manually create a data control hierarchy;

protected internal override void PerformDataBinding(IEnumerable data){     base.PerformDataBinding(data);     this.Controls.Clear();     base.ClearChildViewState();     this.TrackViewState();     int num = this.CreateChildControls(data, true);     base.ChildControlsCreated = true;     this.ViewState["_!ItemCount"] = num;}

In non-binding mode, two parameters are called from the CreateChildControls method:

DummyDataSource dataSource = new DummyDataSource((int) obj2);this.CreateChildControls(dataSource, false);base.ClearChildViewState();

In this case, the second parameter passed to the CreateChildControls method is false, which means that no data is added to the control hierarchy. The ASP. NET sending-back mechanism ensures that each sub-control correctly restores its own values from the view.

Next, observe the overload of the CreateChildControls method defined on the CompositeDataBindControl class:

protected abstract int CreateChildControls (     IEnumerable dataSource,     bool dataBinding)

The parameters of this method are described as follows:

Attribute Description

Attribute

In the final tag, this attribute is permanently stored as an encoded HTML feature.
EncodedInnerDefaultProperty This property is stored as the internal text of the control. The value of this attribute is encoded in HTML. Only strings can be assigned to this attribute.
InnerDefaultProperty It is permanently stored as the property of the internal text in the control and is the default property of the element. Only one property can be specified as the default property.
InnerProperty This property is permanently stored as an embedded tag in the control, which is commonly used for complex objects using templates and styles.

The template attributes are as follows:

private ITemplate _titleTemplate;[PersistenceMode(PersistenceMode.InnerProperty)][TemplateContainer(typeof(TitleTemplateContainer))]public ITemplate TitleTemplate{     get     {         return _titleTemplate;     }     set     {         _titleTemplate = value;     }}
3. Implementation

3.1 create the BarChartItem class in the solution ControlLibrary class library to indicate the control items:

using System;using System.Collections.ObjectModel;using System.Web.UI;using System.Web.UI.WebControls;  public class BarChartItem:TableRow{     public BarChartItem(BarChartItemType itemType)     {         ItemType = itemType;     }      public BarChartItemType ItemType     {         get;         set;     }      public object DataItem     {         get;         set;     }}

3.2 The BarChartItemType enumeration is used in the BarChartItem class to identify the type of the current item (similar to the title and alternate rows in the GridView). Write this enumeration implementation:

Public enum BarChartItemType {Title, // Title SubTitle, // Level 2 Title Item, // data Item Footer // Footer}

3.3 define the collection class BarChartItemCollection of this control item:

public class BarChartItemCollection : Collection<BarChartItem>{}

3.4 to enable users to access data items after creating items and binding data, write custom event parameter classes:

public class BarChartItemEventArgs : EventArgs{     private BarChartItem _item;      public BarChartItemEventArgs(BarChartItem item)     {         _item = item;     }      public BarChartItem Item     {         get         {             return _item;         }     }}

3.5 define the template container class

public class TitleTemplateContainer : WebControl, INamingContainer{     private BarChart _parent;      public TitleTemplateContainer(BarChart parent)     {         _parent = parent;     }      public string Title     {         get         {             return _parent.Title;         }     }      public string SubTitle     {         get         {             return _parent.SubTitle;         }     }      public BarChart BarChart     {         get         {             return _parent;         }     }}

3.6 create a BarChar class in the ControlLibrary class library and define private variables, which inherit from the CompositeDataBoundControl class:

public class BarChart : CompositeDataBoundControl{     public event EventHandler<BarChartItemEventArgs> BarChartItemCreated;     public event EventHandler<BarChartItemEventArgs> BarChartItemDataBound;     private BarChartItemCollection _items;     private ITemplate _titleTemplate;     private TitleTemplateContainer _titleTemplateContainer;     private TableItemStyle _titleStyle;     private TableItemStyle _subtitleStyle;     private TableItemStyle _labelStyle;}

3.7 define related attributes:

Public string DataTextField {get {object o = ViewState ["DataTextField"]; return o = null? String. empty: (string) o;} set {ViewState ["DataTextField"] = value;} public string DataValueField {get {object o = ViewState ["DataValueField"]; return o = null? String. empty: (string) o ;}set {ViewState ["DataValueField"] = value ;}} public BarChartItemCollection Items {get {if (_ items = null) {_ items = new BarChartItemCollection ();} return _ items ;}} [Browsable (false)] [PersistenceMode (PersistenceMode. innerProperty)] [TemplateContainer (typeof (TitleTemplateContainer)] public ITemplate TitleTemplate {get {return _ titleTemplate;} set {_ titleTemplate = Value ;}} public string Title {get {object o = ViewState ["Title"]; return o = null? String. empty: (string) o ;}set {ViewState ["Title"] = value ;}} public string SubTitle {get {object o = ViewState ["SubTitle"]; return o = null? String. empty: (string) o ;}set {ViewState ["SubTitle"] = value ;}} [PersistenceMode (PersistenceMode. innerProperty)] [DesignerSerializationVisibility (DesignerSerializationVisibility. content)] [policyparentproperty (true)] [Description ("title style")] public virtual TableItemStyle TitleStyle {get {if (_ titleStyle = null) {_ titleStyle = new TableItemStyle ();} if (IsTrackingViewState) (IStateManager) _ titleStyle ). trackViewState (); return _ titleStyle;} [PersistenceMode (PersistenceMode. innerProperty)] [DesignerSerializationVisibility (DesignerSerializationVisibility. content)] [policyparentproperty (true)] [Description ("Level 2 Title style")] public virtual TableItemStyle SubTitleStyle {get {if (_ subtitleStyle = null) {_ subtitleStyle = new TableItemStyle ();} if (IsTrackingViewState) (IStateManager) _ subtitleStyle ). trackViewState (); return _ subtitleStyle;} [PersistenceMode (PersistenceMode. innerProperty)] [DesignerSerializationVisibility (DesignerSerializationVisibility. content)] [policyparentproperty (true)] [Description ("tag style")] public virtual TableItemStyle LabelStyle {get {if (_ labelStyle = null) {_ labelStyle = new TableItemStyle (); // Can initialize the style HERE} if (IsTrackingViewState) (IStateManager) _ labelStyle ). trackViewState (); return _ labelStyle ;}}

3.8 define the event response method:

protected virtual void OnBarChartCreated(BarChartItemEventArgs e){     if (BarChartItemCreated != null)         BarChartItemCreated(this, e);}  protected virtual void OnBarChartDataBound(BarChartItemEventArgs e){     if (BarChartItemDataBound != null)         BarChartItemDataBound(this, e);}

3.9 compile a child control hierarchy method:

Protected override int CreateChildControls (IEnumerable dataSource, bool dataBinding) {return CreateControlHierarchy (dataSource, dataBinding);} private int enumerate (IEnumerable dataSource, bool dataBinding) {if (dataSource = null) {RenderEmptyControl (); return 0;} Table t = new Table (); Controls. add (t); // create the title CreateTitle (t); // create a level-2 Title CreateSubTitle (t); // create a data item int totalItems = CreateAllItems (t, dataSource, dataBinding ); return totalItems ;}

3.10 compile the control creation method:

private void RenderEmptyControl(){     LiteralControl lbl = new LiteralControl("??????");     Controls.Add(lbl);}  private void CreateTitle(Table t){     BarChartItem item = new BarChartItem(BarChartItemType.Title);     t.Rows.Add(item);      TableCell cell = new TableCell();     item.Cells.Add(cell);      cell.ColumnSpan = 2;      if (TitleTemplate != null)     {         _titleTemplateContainer = new TitleTemplateContainer(this);         TitleTemplate.InstantiateIn(_titleTemplateContainer);         cell.Controls.Add(_titleTemplateContainer);     }     else     {         cell.Text = Title;     }      item.DataBind();}  private void CreateSubTitle(Table t){     BarChartItem item = new BarChartItem(BarChartItemType.SubTitle);      t.Rows.Add(item);     TableCell cell = new TableCell();     item.Cells.Add(cell);      cell.ColumnSpan = 2;     cell.Text = SubTitle;}  private int CreateAllItems(Table t, IEnumerable data, bool useDataSource){     int itemCount = 0;      Items.Clear();      foreach (object o in data)     {         BarChartItemType itemType = BarChartItemType.Item;         BarChartItem item = CreateBarChartItem(t, itemType, o, useDataSource);          _items.Add(item);          itemCount++;     }      return itemCount;}  private BarChartItem CreateBarChartItem(Table t, BarChartItemType itemType, object dataItem, bool useDataSource){     BarChartItem item = new BarChartItem(itemType);      TableCell labelCell = CreateLabelCell(item);     TableCell valueCell = CreateScoreCell(item);      BarChartItemEventArgs argsCreated = new BarChartItemEventArgs(item);      OnBarChartCreated(argsCreated);      t.Rows.Add(item);      if (useDataSource)     {         item.DataItem = dataItem;          BindLabelCell(labelCell, dataItem);         BindValueCell(valueCell, dataItem);          BarChartItemEventArgs argsData = new BarChartItemEventArgs(item);          OnBarChartDataBound(argsData);     }      return item;}  private TableCell CreateLabelCell(BarChartItem item){     TableCell cell = new TableCell();          item.Cells.Add(cell);      return cell;}  private TableCell CreateScoreCell(BarChartItem item){     TableCell cell = new TableCell();     item.Cells.Add(cell);      string starPath = Page.ClientScript.GetWebResourceUrl(this.GetType(), "ControlLibrary.Image.stars.gif");      Panel panBg = new Panel();     panBg.Style.Add(HtmlTextWriterStyle.Width, "80px");     panBg.Style.Add(HtmlTextWriterStyle.Height, "16px");     panBg.Style.Add(HtmlTextWriterStyle.TextAlign, "left");     panBg.Style.Add(HtmlTextWriterStyle.Overflow, "hidden");     panBg.Style.Add(HtmlTextWriterStyle.BackgroundImage, starPath);     panBg.Style.Add("background-position", "0px -32px");     panBg.Style.Add("background-repeat", "repeat-x");      cell.Controls.Add(panBg);      Panel panCur = new Panel();           panCur.Style.Add(HtmlTextWriterStyle.Height, "16px");     panCur.Style.Add(HtmlTextWriterStyle.BackgroundImage, starPath);     panCur.Style.Add("background-position", "0px 0px");     panCur.Style.Add("background-repeat", "repeat-x");      panBg.Controls.Add(panCur);           return cell;}  private void BindLabelCell(TableCell cell, object dataItem){     if (!string.IsNullOrEmpty(DataTextField))     {         string txt = Convert.ToString(DataBinder.GetPropertyValue(dataItem, DataTextField));         cell.Text = txt;     }}  /// <summary>/// ????????????/// </summary>/// <param name="cell"></param>/// <param name="dataItem"></param>private void BindValueCell(TableCell cell, object dataItem){     Panel panCur = (Panel)cell.Controls[0].Controls[0];     object o = null;      if (!String.IsNullOrEmpty(DataValueField))         o = DataBinder.GetPropertyValue(dataItem, DataValueField);     else         return;     int score = Convert.ToInt32(o);      string width = score * 16 + "px";     panCur.Style.Add(HtmlTextWriterStyle.Width, width);}  protected override void Render(HtmlTextWriter writer){     PrepareControlForRender();     base.Render(writer);}  public void PrepareControlForRender(){     if (Controls.Count != 1)         return;      Table t = (Table)Controls[0];     t.CopyBaseAttributes(this);     if (ControlStyleCreated)         t.ApplyStyle(ControlStyle);      t.Rows[0].Cells[0].MergeStyle(TitleStyle);      t.Rows[1].Cells[0].MergeStyle(SubTitleStyle);      // Apply style to the labels that render team names     for (int i = 2; i < Items.Count; i++)     {         // Style team labels         t.Rows[i].Cells[0].ApplyStyle(LabelStyle);     }}

3.10 declare and define custom controls on the page to preview the results.

<cc:BarChart ID="bar" runat="server" Font-Size="12px" Title="????????">     <TitleTemplate>         <%# Container.Title %>             <small>(<%# DateTime.Now.ToString() %>)</small>     </TitleTemplate></cc:BarChart>

3.11 compile the post code and preview the result:

Protected void Page_Load (object sender, EventArgs e) {if (! IsPostBack) this. bindData ();} private void BindData () {DataTable table = new DataTable (); DataColumn col = new DataColumn ("Comment", typeof (string); table. columns. add (col); col = new DataColumn ("Score", typeof (int); table. columns. add (col); Random ran = new Random (); for (int I = 0; I <10; I ++) {DataRow row = table. newRow (); int num = ran. next (0, 6); row [0] = "data" + I + "," + num + "star"; row [1] = num; table. rows. add (row);} table. acceptChanges (); bar. dataSource = table; bar. dataTextField = "Comment"; bar. dataValueField = "Score"; bar. dataBind ();}
4. Summary

The complex data binding control can be implemented by extending the CompositeDataBindControl class. This class has a special CreateChildControls Method for Data Binding and recovery. In the next task, we will try to extend DataList and GridView to implement custom paging controls.

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

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.