温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

ASP.NET中怎么实现一个数据绑定控件

发布时间:2021-07-16 11:18:12 来源:亿速云 阅读:147 作者:Leah 栏目:编程语言

本篇文章给大家分享的是有关ASP.NET中怎么实现一个数据绑定控件,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

ASP.NET数据绑定控件一.回顾

如果你使用过ASP.NET内置的数据控件(如DataList,Repeater),你一定会这么做

1.设置数据源 DataSource属性

2.调用数据绑定  DataBind方法

3.在控件的不同模板内使用绑定语法显示数据

这三步应该是必须要做的

其他更多的

你可能需要对绑定的数据进行统一的一些操作(如时间格式化),或者对数据的某一项进行操作(对某一项进行格式化),或者需要触发模板控件内的一些事件(如databound事件).

根据上面的一些需求,我们需要这样做

1.对绑定的数据进行统一的一些操作: 为数据绑定控件定义Item项(表示列表的一条数据, 如Repeater的RepeaterItem)

2.对数据的某一项进行操作: 因为定义了Item项,那你肯定需要一个ItemCollection集合,其可以方便的为你检索数据

3.因为定义了RepeaterItem,原先的EventArgs和CommandEventArgs已经无法满足需求,我们需要自定义委托及其一个为控件提供数据的的ItemEventArgs

上面三点有些并非必须定义,如第2点,还需要根据具体需求来定.但一个完成的控件是需要的.

ASP.NET数据绑定控件二.为数据控件做好准备

这次的demo为不完整的Datalist控件,来源还是MSDN的例子,我们命名为TemplatedList,此控件未定义ItemCollection集合

好了,根据上面的分析我们先为TemplatedList提供项和委托及为事件提供数据的几个EventArgs,请看下面类图

ASP.NET中怎么实现一个数据绑定控件

1.TemplatedListCommandEventArgs为Command事件提供数据

2.TemplatedListItemEventArgs为一般项提供数据

3.TemplatedListItem表示TemplatedList的项

ASP.NET数据绑定控件三.编写TemplatedList

1.TemplatedList主要功能简介

提供一个ItemTemplate模板属性,提供三种不同项样式,ItemCommand 事件冒泡事件及4个事件

ASP.NET中怎么实现一个数据绑定控件

2.实现主要步骤

以下为必须

(1)控件必须实现 System.Web.UI.INamingContainer 接口

(2)定义至少一个模板属性

(3)定义DataSource数据源属性

(4)定义控件项DataItem,即模板的一个容器

(5)重写DataBind 方法及复合控件相关方法(模板控件为特殊的复合控件)

当然还有其他额外的属性,样式,事件

3.具体实现

下面我们来具体看实现方法

(1)定义控件成员属性

#region 静态变量           private static readonly object EventSelectedIndexChanged = new object();          private static readonly object EventItemCreated = new object();          private static readonly object EventItemDataBound = new object();          private static readonly object EventItemCommand = new object();          #endregion           成员变量#region 成员变量          private IEnumerable dataSource;          private TableItemStyle itemStyle;          private TableItemStyle alternatingItemStyle;          private TableItemStyle selectedItemStyle;          private ITemplate itemTemplate;          #endregion           控件属性#region 控件属性           [          Category("Style"),          Description("交替项样式"),          DesignerSerializationVisibility(DesignerSerializationVisibility.Content),          NotifyParentProperty(true),          PersistenceMode(PersistenceMode.InnerProperty),          ]          public virtual TableItemStyle AlternatingItemStyle          {              get             {                  if (alternatingItemStyle == null)                  {                      alternatingItemStyle = new TableItemStyle();                      if (IsTrackingViewState)                          ((IStateManager)alternatingItemStyle).TrackViewState();                  }                  return alternatingItemStyle;              }          }            [          Category("Style"),          Description("一般项样式"),          DesignerSerializationVisibility(DesignerSerializationVisibility.Content),          NotifyParentProperty(true),          PersistenceMode(PersistenceMode.InnerProperty),          ]          public virtual TableItemStyle ItemStyle          {              get             {                  if (itemStyle == null)                  {                      itemStyle = new TableItemStyle();                      if (IsTrackingViewState)                          ((IStateManager)itemStyle).TrackViewState();                  }                  return itemStyle;              }          }           [           Category("Style"),           Description("选中项样式"),           DesignerSerializationVisibility(DesignerSerializationVisibility.Content),           NotifyParentProperty(true),           PersistenceMode(PersistenceMode.InnerProperty),           ]          public virtual TableItemStyle SelectedItemStyle          {              get             {                  if (selectedItemStyle == null)                  {                      selectedItemStyle = new TableItemStyle();                      if (IsTrackingViewState)                          ((IStateManager)selectedItemStyle).TrackViewState();                  }                  return selectedItemStyle;              }          }             [          Bindable(true),          Category("Appearance"),          DefaultValue(-1),          Description("The cell padding of the rendered table.")          ]          public virtual int CellPadding          {              get             {                  if (ControlStyleCreated == false)                  {                      return -1;                  }                  return ((TableStyle)ControlStyle).CellPadding;              }              set             {                  ((TableStyle)ControlStyle).CellPadding = value;              }          }           [          Bindable(true),          Category("Appearance"),          DefaultValue(0),          Description("The cell spacing of the rendered table.")          ]          public virtual int CellSpacing          {              get             {                  if (ControlStyleCreated == false)                  {                      return 0;                  }                  return ((TableStyle)ControlStyle).CellSpacing;              }              set             {                  ((TableStyle)ControlStyle).CellSpacing = value;              }          }             [          Bindable(true),          Category("Appearance"),          DefaultValue(GridLines.None),          Description("The grid lines to be shown in the rendered table.")          ]          public virtual GridLines GridLines          {              get             {                  if (ControlStyleCreated == false)                  {                      return GridLines.None;                  }                  return ((TableStyle)ControlStyle).GridLines;              }              set             {                  ((TableStyle)ControlStyle).GridLines = value;              }          }           [          Bindable(true),          Category("Data"),          DefaultValue(null),          Description("数据源"),          DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)          ]          public IEnumerable DataSource          {              get             {                  return dataSource;              }              set             {                  dataSource = value;              }          }            [          Browsable(false),          DefaultValue(null),          Description("项模板"),          PersistenceMode(PersistenceMode.InnerProperty),          TemplateContainer(typeof(TemplatedListItem))          ]          public virtual ITemplate ItemTemplate          {              get             {                  return itemTemplate;              }              set             {                  itemTemplate = value;              }          }            [          Bindable(true),          DefaultValue(-1),          Description("选中项索引,默认为-1")          ]          public virtual int SelectedIndex          {              get             {                  object o = ViewState["SelectedIndex"];                  if (o != null)                      return (int)o;                  return -1;              }              set             {                  if (value < -1)                  {                      throw new ArgumentOutOfRangeException();                  }                  //获取上次选中项                  int oldSelectedIndex = SelectedIndex;                  ViewState["SelectedIndex"] = value;                   if (HasControls())                  {                      Table table = (Table)Controls[0];                      TemplatedListItem item;                       //第一次选中项不执行                      if ((oldSelectedIndex != -1) && (table.Rows.Count > oldSelectedIndex))                      {                          item = (TemplatedListItem)table.Rows[oldSelectedIndex];                          //判断项类型,为了将选中项还原为数据项                          if (item.ItemType != ListItemType.EditItem)                          {                              ListItemType itemType = ListItemType.Item;                              if (oldSelectedIndex % 2 != 0)                                  itemType = ListItemType.AlternatingItem;                              item.SetItemType(itemType);                          }                      }                      //第一次执行此项,并一直执行                      if ((value != -1) && (table.Rows.Count > value))                      {                          item = (TemplatedListItem)table.Rows[value];                          item.SetItemType(ListItemType.SelectedItem);                      }                  }              }          }              #endregion

成员如下(可以看上面类图)

1.三个项样式和三个样式属性

2.公开DataSource数据源属性,一个模板属性

3.SelectedIndex索引属性

前面的相信大家都很容易明白,其中的三个项样式我们需要为其重写视图状态管理,不熟悉可以看以前的随笔,这里不再重复.

SelectedIndex属性比较复杂,这里重点介绍此属性

SelectedIndex索引属性默认为-1,

我给出了注释,在赋值前先记录下了上次的选中项,为恢复样式而做准备

//获取上次选中项   int oldSelectedIndex = SelectedIndex;   ViewState["SelectedIndex"] = value;

当第一次更改SelectedIndex属性时只执行下列代码(将此项标记为选中项),因为初始化时的没有oldSelectedIndex,不需要恢复样式

//第一次执行此项,并一直执行                      if ((value != -1) && (table.Rows.Count > value))                      {                          item = (TemplatedListItem)table.Rows[value];                          item.SetItemType(ListItemType.SelectedItem);                      }

再次执行时,恢复oldSelectedIndex选中项样式

//第一次选中项不执行  if ((oldSelectedIndex != -1) && (table.Rows.Count > oldSelectedIndex))  {      item = (TemplatedListItem)table.Rows[oldSelectedIndex];      //判断项类型,为了将选中项还原为数据项      if (item.ItemType != ListItemType.EditItem)      {          ListItemType itemType = ListItemType.Item;          if (oldSelectedIndex % 2 != 0)              itemType = ListItemType.AlternatingItem;          item.SetItemType(itemType);      }  }

相信这样的解释你会明白

(2)定义控件成员事件

我们可以用上刚才我们声明的委托了,即然你定义了这么多事件,就该为其安排触发的先后.所以这个要特别注意,等下会再次提到.

#region 事件          protected virtual void OnItemCommand(TemplatedListCommandEventArgs e)          {              TemplatedListCommandEventHandler onItemCommandHandler = (TemplatedListCommandEventHandler)Events[EventItemCommand];              if (onItemCommandHandler != null) onItemCommandHandler(this, e);          }           protected virtual void OnItemCreated(TemplatedListItemEventArgs e)          {              TemplatedListItemEventHandler onItemCreatedHandler = (TemplatedListItemEventHandler)Events[EventItemCreated];              if (onItemCreatedHandler != null) onItemCreatedHandler(this, e);          }           protected virtual void OnItemDataBound(TemplatedListItemEventArgs e)          {              TemplatedListItemEventHandler onItemDataBoundHandler = (TemplatedListItemEventHandler)Events[EventItemDataBound];              if (onItemDataBoundHandler != null) onItemDataBoundHandler(this, e);          }           protected virtual void OnSelectedIndexChanged(EventArgs e)          {              EventHandler handler = (EventHandler)Events[EventSelectedIndexChanged];              if (handler != null) handler(this, e);          }           [          Category("Action"),          Description("Raised when a CommandEvent occurs within an item.")          ]          public event TemplatedListCommandEventHandler ItemCommand          {              add              {                  Events.AddHandler(EventItemCommand, value);              }              remove              {                  Events.RemoveHandler(EventItemCommand, value);              }          }           [          Category("Behavior"),          Description("Raised when an item is created and is ready for customization.")          ]          public event TemplatedListItemEventHandler ItemCreated          {              add              {                  Events.AddHandler(EventItemCreated, value);              }              remove              {                  Events.RemoveHandler(EventItemCreated, value);              }          }           [          Category("Behavior"),          Description("Raised when an item is data-bound.")          ]          public event TemplatedListItemEventHandler ItemDataBound          {              add              {                  Events.AddHandler(EventItemDataBound, value);              }              remove              {                  Events.RemoveHandler(EventItemDataBound, value);              }          }           [          Category("Action"),          Description("Raised when the SelectedIndex property has changed.")          ]          public event EventHandler SelectedIndexChanged          {              add              {                  Events.AddHandler(EventSelectedIndexChanged, value);              }              remove              {                  Events.RemoveHandler(EventSelectedIndexChanged, value);              }          }          #endregion

(3)关键实现

我们为控件提供了这么多东西,剩下的事情就是要真正去实现功能了

1.重写DataBind方法

当控件绑定数据时首先会执行此方法触发DataBinding事件

//控件执行绑定时执行  public override void DataBind()  {       base.OnDataBinding(EventArgs.Empty);       //移除控件      Controls.Clear();      //清除视图状态信息      ClearChildViewState();       //创建一个带或不带指定数据源的控件层次结构      CreateControlHierarchy(true);      ChildControlsCreated = true;       TrackViewState();  }

2.CreateControlHierarchy方法

/**//// <summary>   /// 创建一个带或不带指定数据源的控件层次结构   /// </summary>   /// <param name="useDataSource">指示是否要使用指定的数据源</param>   //注意:当第二次执行数据绑定时,会执行两遍   private void CreateControlHierarchy(bool useDataSource)   {       IEnumerable dataSource = null;       int count = -1;         if (useDataSource == false)       {           // ViewState must have a non-null value for ItemCount because this is checked            //  by CreateChildControls.           count = (int)ViewState["ItemCount"];           if (count != -1)           {               dataSource = new DummyDataSource(count);           }       }       else      {           dataSource = this.dataSource;       }        //根据项类型开始创建子控件       if (dataSource != null)       {           Table table = new Table();           Controls.Add(table);            //选中项索引           int selectedItemIndex = SelectedIndex;           //项索引           int index = 0;           //项数量           count = 0;           foreach (object dataItem in dataSource)           {                ListItemType itemType = ListItemType.Item;               if (index == selectedItemIndex)               {                                     itemType = ListItemType.SelectedItem;               }               else if (index % 2 != 0)               {                   itemType = ListItemType.AlternatingItem;               }                //根据不同项索引创建样式               CreateItem(table, index, itemType, useDataSource, dataItem);               count++;               index++;           }       }       //执行绑定时执行时执行       if (useDataSource)       {           //保存项数量           ViewState["ItemCount"] = ((dataSource != null) ? count : -1);       }   }     //创建项   private TemplatedListItem CreateItem(Table table, int itemIndex, ListItemType itemType, bool dataBind, object dataItem)   {       TemplatedListItem item = new TemplatedListItem(itemIndex, itemType);       TemplatedListItemEventArgs e = new TemplatedListItemEventArgs(item);        if (itemTemplate != null)       {           itemTemplate.InstantiateIn(item.Cells[0]);       }       if (dataBind)       {           item.DataItem = dataItem;       }       //注意事件触发顺序       OnItemCreated(e);       table.Rows.Add(item);        if (dataBind)       {           item.DataBind();           OnItemDataBound(e);            item.DataItem = null;       }        return item;   }

CreateItem方法辅助用于创建项模板,此处注意事件触发顺序,上面已经提到过

此方法根据项索引创建控件中不同的Item项 ,ViewState["ItemCount"]表示项的数量,第一次触发时或者重新执行DataBind方法时方法参数为true,并在初始化以后(回发期间)CreateChildControls方法会调用此方法,其参数为false

数据源不再是实际的数据源,而是新定义的DummyDataSource,其主要实现了一个迭代

internal sealed class DummyDataSource : ICollection      {           private int dataItemCount;           public DummyDataSource(int dataItemCount)          {              this.dataItemCount = dataItemCount;          }           public int Count          {              get             {                  return dataItemCount;              }          }           public bool IsReadOnly          {              get             {                  return false;              }          }           public bool IsSynchronized          {              get             {                  return false;              }          }           public object SyncRoot          {              get             {                  return this;              }          }           public void CopyTo(Array array, int index)          {              for (IEnumerator e = this.GetEnumerator(); e.MoveNext(); )                  array.SetValue(e.Current, index++);          }           public IEnumerator GetEnumerator()          {              return new DummyDataSourceEnumerator(dataItemCount);          }           private class DummyDataSourceEnumerator : IEnumerator          {               private int count;              private int index;               public DummyDataSourceEnumerator(int count)              {                  this.count = count;                  this.index = -1;              }               public object Current              {                  get                 {                      return null;                  }              }               public bool MoveNext()              {                  index++;                  return index < count;              }               public void Reset()              {                  this.index = -1;              }          }      }

原因很明显,为了减少对数据源的访问,所以我们平时操作数据的时候,必须重新执行DataBind方法,原因就在此

好了,到了这里差不多主要的事情我们已经完成.接着把剩下的也完成

3.呈现

又到了Render方法这里了

此方法体只要执行了PrepareControlHierarchy方法,不同的方法做不同的事情,CreateControlHierarchy方法根据索引值指定了不同的项,PrepareControlHierarchy则为不同项呈现不同的样式效果

//为不同类型项加载样式  private void PrepareControlHierarchy()  {      if (HasControls() == false)      {          return;      }       Debug.Assert(Controls[0] is Table);      Table table = (Table)Controls[0];       table.CopyBaseAttributes(this);      if (ControlStyleCreated)      {          table.ApplyStyle(ControlStyle);      }       // The composite alternating item style; do just one      // merge style on the actual item.      Style altItemStyle = null;      if (alternatingItemStyle != null)      {          altItemStyle = new TableItemStyle();          altItemStyle.CopyFrom(itemStyle);          altItemStyle.CopyFrom(alternatingItemStyle);      }      else     {          altItemStyle = itemStyle;      }       int rowCount = table.Rows.Count;      for (int i = 0; i < rowCount; i++)      {          TemplatedListItem item = (TemplatedListItem)table.Rows[i];          Style compositeStyle = null;          //根据不同项加载不同样式          switch (item.ItemType)          {              case ListItemType.Item:                  compositeStyle = itemStyle;                  break;               case ListItemType.AlternatingItem:                  compositeStyle = altItemStyle;                  break;               case ListItemType.SelectedItem:                  {                      compositeStyle = new TableItemStyle();                       if (item.ItemIndex % 2 != 0)                          compositeStyle.CopyFrom(altItemStyle);                      else                         compositeStyle.CopyFrom(itemStyle);                      compositeStyle.CopyFrom(selectedItemStyle);                  }                  break;          }           if (compositeStyle != null)          {              item.MergeStyle(compositeStyle);          }      }  }   //控件呈现  protected override void Render(HtmlTextWriter writer)  {      // Apply styles to the control hierarchy      // and then render it out.       // Apply styles during render phase, so the user can change styles      // after calling DataBind without the property changes ending      // up in view state.      PrepareControlHierarchy();       RenderContents(writer);  }

终于差不多了,经过这么多步骤,我们终于完成了,让我们来使用控件,看一下效果

ASP.NET中怎么实现一个数据绑定控件

以上就是ASP.NET中怎么实现一个数据绑定控件,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI