Asp.net自定义控件开发任我行(8)-数据集绑定
摘要
已经有好几天没有写博客了,今天继续,前几天写到了注册自定义事件,今天我们来讲数据集绑定。
先把运行效果截个图给大家看,让大家心里也有个底。(大家要从第一章开始看起,我们每一章都是接着前面没做完的,一步步的完善)
内容
在ASP.NET数据绑定控件分为三种:
- 简单数据绑定:简单数据绑定将一个对象与某个控件的属性绑定在一起。数据源只是绑定单个数据项,而不是绑定一个数据项列表。简单数据绑定使用数据绑定表达式完成,数据绑定表达式是用<%#...%>封装的任何可执行代码。
- 列表控件:列表控件是通过一个固定不变的用户界面显示一个数据项列表的控件。常见的列表控件包含RadioButtonList控件、CheckBoxList控件和ASP.NET2.0中新引入的BulletedList控件。
- 复杂数据绑定:复杂数据绑定控件通常是显示一组数据项的组合控件,它们有着灵活的呈现机制,例如GridView控件就是一个复杂数据绑定控件。
我们这里只讲第3种数据绑定,使用时数据绑定方法代码看起来可能如下所示
- protected void Page_Load(object sender, EventArgs e)
- {
- if (!IsPostBack)
- {
- DataTable dt = new DataTable();
- dt.Columns.Add("name");
- dt.Columns.Add("id");
- DataRow dr = dt.NewRow();
- dr[] = "张三1";
- dr[] = ;
- dt.Rows.Add(dr);
DataRow dr1 = dt.NewRow();- dr1[] = "张三2";
- dr1[] = ;
- dt.Rows.Add(dr1);
- DataRow dr2 = dt.NewRow();
- dr2[] = "张三3";
- dr2[] = ;
- dt.Rows.Add(dr2);
- DataRow dr3 = dt.NewRow();
- dr3[] = "张三4";
- dr3[] = ;
- dt.Rows.Add(dr3);
- DropDwonCheckList1.DataTextField = "name";
- DropDwonCheckList1.DataValueField = "id";
- DropDwonCheckList1.DataSource = dt;
- DropDwonCheckList1.DataBind();
}- }
- <form id="form1" runat="server">
- <XYB:DropDwonCheckList ID="DropDwonCheckList1" runat="server" />
- </form>
我们都知道DropDwonList,CheckBoxList等这些控件都可以绑定数据源,我们先看看他们底层是什么样子的,
- public class DropDownList : ListControl, IPostBackDataHandler
- public class CheckBoxList : ListControl, IRepeatInfoUser, INamingContainer, IPostBackDataHandler
- public abstract class ListControl : DataBoundControl, IEditableTextControl, ITextControl
我们可以看到,DropDwonList,CheckBoxList都继承了ListControl,而ListControl继承了DataBoundControl类。我们再来看看他们的Asp.net2.0提供的数据集绑定类的层次结构图
所以我们在原来项目的基础上做修改,继承DataBoundControl类,这个类里面有我们想要的DataSource和DataSourceID属性,提供DataBind方法,并且只要我们执行DataBind()方法时,自动执行绑定。
1.重新继承DataBoundControl,代码如下
- public class DropDwonCheckList:DataBoundControl,IPostBackEventHandler,INamingContainer
IPostBackEventHandler 是用于处理点击回发事件的接口,我们在上一章的注册自定义事件里面详细介绍过了。INamingContainer接口只为解决控件ID命名冲突问题。
2.定义属性
- [Description("要显示的文本项"), Category("数据")]
- public string DataTextField
- {
- get { return ViewState["DataTextField"].ToString() ?? "name"; }
- set { ViewState["DataTextField"] = value; }
- }
- [Description("文本关联值"), Category("数据")]
- public string DataValueField
- {
- get { return ViewState["DataValueField"].ToString() ?? "id"; }
- set { ViewState["DataValueField"] = value; }
- }
- [Description("下拉框的高度"),Category("下拉框")]
- public int DropDwonHeight
- {
- get { return Convert.ToInt32(ViewState["DropDwonHeight"] ?? ); }
- set { ViewState["DropDwonHeight"] = value; }
- }
- [Description("下拉框的宽度"),Category("下拉框")]
- public int DropdwonWidth
- {
- get { return ViewState["DropdwonWidth"] == null ? : Convert.ToInt32(ViewState["DropdwonWidth"]); }
- set { ViewState["DropdwonWidth"] = value; }
- }
3.实现IPostBackEventHandler 接口,我在这里就直接把代码粘出来了,这个不是我们本章的重点,旨在读者看到后,有个印象,起到复习的作用,最后大家不要忘记导火线,用这个导火线来产生事件回发。我们只需为控件在页面类中注册onclick事件。
Control.Attributes["onclick"]=this.Page.GetPostBackEventReference(this);//引发回发
- #region 行为与事件
- private static readonly object EventClick = new object();//键值对象,指明点击事件,名称随便取
- [Description("点击文本框时发生"), Category("Action")]
- public event EventHandler Click
- {
- add
- {
- base.Events.AddHandler(EventClick, value);
- }
- remove
- {
- base.Events.RemoveHandler(EventClick, value);
- }
- }
- protected virtual void OnClick(EventArgs e)
- {
- EventHandler handler = (EventHandler)base.Events[EventClick];
- if (handler != null)
- {
- handler(this, e);
- }
- }
- #endregion
- void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
- {
- this.OnClick(new EventArgs());
- }
4.定义数据项。
我们都知道DropDwonList控件的数据项是ListItem,当然我们DropDwonCheckList控件(我们最终要实现的控件) 也要定义一个数据项。新建一个类,命名为CheckDataItem,因为我们要保存CheckDataItem的数据状态,所以我们还需继承一个IStateManager接口,ViewState不能很好的保存一个对象,IStateManager 是保存对象状态的最佳选择,代码如下。
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Web.UI.WebControls;
- using System.Web.UI;
- using System.Runtime;
- namespace XYB.Controls
- {
- public class CheckDataItem:IStateManager
- {
- #region 字段与属性
- private bool _mark;
- /// <summary>
- /// 要显示的文本项
- /// </summary>
- public string ItemText { get; set; }
- /// <summary>
- /// 文本关联值
- /// </summary>
- public string ItemValue { get; set; }
- /// <summary>
- /// 该数据项是否被选中
- /// </summary>
- public bool Checked { get; set; }
- #endregion
- #region 构造函数
- [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
- public CheckDataItem()
- : this(null, null)
- {
- }
- [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
- public CheckDataItem(string text)
- : this(text, null)
- {
- }
- [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
- public CheckDataItem(string text, string value)
- : this(text, value, false)
- {
- }
- [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
- public CheckDataItem(string text, string value, bool isChecked)
- {
- this.ItemText = text;
- this.ItemValue = value;
- this.Checked = isChecked;
- }
- #endregion
- /// <summary>
- /// 指示服务器控件是否正在发生改变
- /// </summary>
- public bool IsTrackingViewState
- {
- get { return _mark; }
- }
- /// <summary>
- /// 将服务器控件还原到保存前的视图状态
- /// </summary>
- /// <param name="state"></param>
- public void LoadViewState(object state)
- {
- if (state != null)
- {
- Triplet t = state as Triplet;
- ItemText = t.First.ToString();
- ItemValue = t.Second.ToString();
- Checked = Convert.ToBoolean(t.Third);
- }
- }
- /// <summary>
- /// 将服务器控件的视图状态保存到 Object
- /// </summary>
- /// <returns></returns>
- public object SaveViewState()
- {
- return new Triplet(ItemText, ItemValue, Checked);
- }
- /// <summary>
- /// 指示服务器控跟踪其视图状态更改
- /// </summary>
- public void TrackViewState()
- {
- _mark = true;
- }
- }
- }
Triplet 类是用于保存三个相关联的Object对象,多个对象用数组来保存,LoadViewState是还原状态,先将其强制成Triplet对象,然后再从Triplet三个对象中取值,达到还原的目的,SaveViewState保存状态,我们直接返回一个Triplet对象。记住这三个关联对象顺序要一致。
5.定义数据集合。
ListItem保存在ListItemCollection中,于是我们的CheckDataItem也需要保存在CheckDataItemColllection中。新建一个类,命名为CheckDataItemCollection。CheckDataItemCollection需要继承一个Collection泛型集合,使用泛型的好处在我们找工作的时候经常在面试题中提到,好处就是只让添加一种类型,安全性类型,减少装箱拆箱所带来的开销(顺便在这里扯一下,嘿嘿)。CheckDataItemCollection只让添加CheckDataItem这一种类型,同时我们也还需要实现IStateManager接口,来保存这个集合。代码如下
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Collections;
- using System.Collections.ObjectModel;
- using System.Web.UI;
- namespace XYB.Controls
- {
- public class CheckDataItemCollection : Collection<CheckDataItem>, IStateManager
- {
- private bool marked;
- public CheckDataItemCollection()
- {
- 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[] ItemTexts = (string[])trip.First;
- string[] ItemValues = (string[])trip.Second;
- bool[] ItemCheckeds = (bool[])trip.Third;
- for (int i = ; i < ItemCheckeds.Length; i++)
- {
- Add(new CheckDataItem(ItemTexts[i], ItemValues[i], ItemCheckeds[i]));
- }
- }
- public object SaveViewState()
- {
- int num = Count;
- object[] ItemTexts = new string[num];
- object[] ItemValues = new string[num];
- bool[] ItemCheckeds = new bool[num];
- for (int i = ; i < num; i++)
- {
- ItemTexts[i] = Items[i].ItemText;
- ItemValues[i] = Items[i].ItemValue;
- ItemCheckeds[i] = Items[i].Checked;
- }
- return new Triplet(ItemTexts, ItemValues, ItemCheckeds);
- }
- }
- }
我们把CheckDataItemCollection定义好了,回到DropDwonCheckList.cs文件中来,现在我们来定义一个变量Items,它就是用来保存所有的CheckDataItem数据项。
- private CheckDataItemCollection _items;
- public CheckDataItemCollection Items
- {
- get
- {
- if (_items == null)
- {
- _items = new CheckDataItemCollection();
- }
- if (IsTrackingViewState)
- {
- _items.TrackViewState();
- }
- return _items;
- }
- }
5.从数据源中读取数据,并进行绑定。
我们可能在疑惑,我们传值给DataSouce,而DataSouce是一个Object类型,而且它又是如何把值给Items的呢,DataBoundControl类为我们提供了一个方法PerformDataBinding,此方法根据映射从数据源迭代读取数据,并在执行了DataBind方法后自动执行。我们只需要重写这个方法即可,并在这里作一些手脚。
- /// <summary>
- /// 重写PerformDataBinding方法根据映射从数据源迭代读取数据,此方法在数据绑定时执行
- /// </summary>
- /// <param name="data"></param>
- protected override void PerformDataBinding(IEnumerable data)
- {
- base.PerformDataBinding(data);
- if (data != null)
- {
- foreach (object o in data)
- {
- CheckDataItem item = new CheckDataItem();
- item.ItemText = DataBinder.GetPropertyValue(o, DataTextField, null);
- item.ItemValue = DataBinder.GetPropertyValue(o, DataValueField, null);
- item.Checked = false;
- Items.Add(item);
- }
- }
- }
该方法接收IEnumerable类型的参数用于迭带访问数据源中的数据,在读取数据源中的数据时使用了DataBinder类,该类上有一个实用的GetPropertyValue方法,用于根据属性反射的读取数据源中的值,此处我们使用该方法并传递了DataTextField和DataValueField以读取文本和文本所关联的值。
6.重写LoadViewState,和SaveViewState方法将CheckDataItem数据项保存到视图状态中并能够正确的恢复。
- protected override object SaveViewState()
- {
- return new Pair(base.SaveViewState(), Items.SaveViewState());
- }
- protected override void LoadViewState(object savedState)
- {
- if (savedState != null)
- {
- Pair p = (Pair)savedState;
- base.LoadViewState(p.First);
- Items.LoadViewState(p.Second);
- }
- }
Pair类是用于保存两个相关联的Object对象。
7.呈现控件,大功生成。
我们可以把我们的最终控件分成四部分,文本框部分,头部,内容部,和尾部。
- #region 重写呈现
- protected override void OnPreRender(EventArgs e)
- {
- base.OnPreRender(e);
- //如果文件已经被加载了,就不用重复加载
- if (!this.Page.ClientScript.IsClientScriptIncludeRegistered(this.GetType(), "XYB.Controls.JS.dropDwon.js"))
- {
- #region 加载嵌入资源.css文件
- //加载嵌入资源.css文件
- string cssHref = this.Page.ClientScript.GetWebResourceUrl(this.GetType(), "XYB.Controls.CSS.dropDwon.css");
- string cssLink = string.Format("<link href='{0}' rel='stylesheet' type='text/css' />", cssHref);
- LiteralControl litLink = new LiteralControl(cssLink);
- litLink.ID = "XYB_Controls_dropDwonCss";
- this.Page.Header.Controls.Add(litLink);
- #endregion
- //加载嵌入资源.js文件
- this.Page.ClientScript.RegisterClientScriptResource(this.GetType(), "XYB.Controls.JS.dropDwon.js");
- //this.Attributes["onclick"] = "dropDwonClick()";//给文本框注册点击事件
- //调用GetPostBackEventReference方法,产生页面回发。
- //this.Attributes["onclick"] = this.Page.GetPostBackEventReference(this);
- }
- }
- protected override void Render(HtmlTextWriter writer)
- {
- HtmlInputText txt = new HtmlInputText();
- txt.Style.Add(HtmlTextWriterStyle.Width, DropdwonWidth + "px");
- this.Controls.Add(txt);
- Panel pnlDropDown = new Panel();
- //名字写这么长,只为防止别人与我的控件ID相同
- pnlDropDown.ID = "XYB_Controls_DropDownPanelID";
- pnlDropDown.Style["height"] = "auto";
- pnlDropDown.Width = DropdwonWidth;
- pnlDropDown.Style["border"] = "1px solid #ccc";
- CreateControlHierarchy(pnlDropDown);
- this.Controls.Add(pnlDropDown);
- base.Render(writer);
- }
- /// <summary>
- /// 创建控件层次结构,头部,内容部,尾部
- /// </summary>
- /// <param name="dropDwonPanel"></param>
- private void CreateControlHierarchy(Panel dropDwonPanel)
- {
- CreateHeaderTemplate(dropDwonPanel);
- CreateContentTemplate(dropDwonPanel);
- CreateFooterTemplate(dropDwonPanel);
- }
- /// <summary>
- /// 创建头部
- /// </summary>
- /// <param name="dropDwonPanel"></param>
- private void CreateHeaderTemplate(Panel dropDwonPanel)
- {
- StringBuilder strHeaderHtml = new StringBuilder();
- strHeaderHtml.Append("<div id=\"XYB_Controls_DropDownHeaderPanelID\">");
- strHeaderHtml.Append("<input type='checkbox' id='XYB_Controls_SelectAllItemCheckBox' /><label>全选</label>");
- strHeaderHtml.Append("</div>");
- dropDwonPanel.Controls.Add(new LiteralControl(strHeaderHtml.ToString()));
- }
- /// <summary>
- /// 创建内容部
- /// </summary>
- /// <param name="dropDwonPanel"></param>
- private void CreateContentTemplate(Panel dropDwonPanel)
- {
- if (Items.Count>)
- {
- foreach (CheckDataItem item in Items)
- {
- Panel contentPanel = new Panel();
- contentPanel.Style["width"] = "100%";
- contentPanel.Style["text-align"] = "left";
- contentPanel.Style["padding-left"] = "5px";
- CheckBox cbx = new CheckBox();
- cbx.Text = item.ItemText;
- contentPanel.Controls.Add(cbx);
- dropDwonPanel.Controls.Add(contentPanel);
- }
- }
- }
- /// <summary>
- /// 创建尾部
- /// </summary>
- /// <param name="dropDwonPanel"></param>
- private void CreateFooterTemplate(Panel dropDwonPanel)
- {
- StringBuilder strFooterHtml = new StringBuilder();
- strFooterHtml.Append("<div id='XYB_Controls_DropDwonFooterPanelID'>");
- strFooterHtml.Append("<div id=\"XYB_Controls_DropDwonFooterLeftPanelID\">");
- strFooterHtml.Append("<input type=\"button\" id=\"XYB_Controls_btnSure\" value=\"确定\" />");
- strFooterHtml.Append("</div>");
- strFooterHtml.Append("<div id=\"XYB_Controls_DropDwonFooterRightPanelID\">");
- strFooterHtml.Append("<input type=\"button\" id=\"XYB_Controls_btnCancel\" value=\"取消\" />");
- strFooterHtml.Append("</div>");
- strFooterHtml.Append("</div>");
- dropDwonPanel.Controls.Add(new LiteralControl(strFooterHtml.ToString()));
- }
dropDwon.js代码
- function dropDwonClick() {
- $("XYB_Controls_DropDownPanelID").style.display = "block";
- }
- function $(obj) {
- return document.getElementById(obj);
- }
dropDwon.css代码
- #XYB_Controls_DropDownPanelID{
- border:1px solid #ccc;
- display:block;
- }
- #XYB_Controls_DropDownHeaderPanelID,#XYB_Controls_DropDownFooterPanelID{
- height:20px; line-height:20px;width:%;
- }
- #XYB_Controls_DropDwonFooterLeftPanelID,#XYB_Controls_DropDwonFooterRightPanelID{
- width:%;float:left;text-align:center;
- }
- #XYB_Controls_DropDownHeaderPanelID
- {
- border-bottom:1px solid #ccc;
- }
- #XYB_Controls_DropDwonFooterPanelID
- {
- padding-top:10px;
- height:30px;
- line-height:30px;
- }
下集预告
上面的代码就是我全部的页面代码。运行起来的效果就是摘要的截图,下一章,全选与反选
Asp.net自定义控件开发任我行(8)-数据集绑定的更多相关文章
- Asp.net自定义控件开发任我行(附1)-属性一览众山小
元数据属性应用于服务器控件及其成员,从而提供由设计工具.ASP.NET 页分析器.ASP.NET 运行库以及公共语言运行库使用的信息.当页开发人员在可视化设计器中使用控件时,设计时属性能改进开发人员的 ...
- Asp.net自定义控件开发任我行(4)-ViewState保存控件状态
摘要 上一篇我们实现了下拉框的效果,此章的目的主要是保存控件属性状态 内容 我们先来看一个例子,后台代码不变,我们只改UI页面的代码,先在页面上拖放两个控件,一个是我们现在要开发的这个控件,另一个是按 ...
- Asp.net自定义控件开发任我行(2)-TagPrefix标签
摘要 前面我们已经做了一个最简单的TextBox的马甲,此篇文章,我们来讲讲自定义控件的标签.大家可能看到了上一篇中拖放进来的代码是 <cc1:TextEdit ID="TextEdi ...
- Asp.net自定义控件开发任我行(7)-注册自定义事件
摘要 前面我们已经把嵌入资源讲完了,不知道大家有没有得到收益,本章主要讲自定义事件,也就是给TextBox注册一个点击事件. 引言 不知道道上的朋友有没有注意到TextBox控件没有点击事件,就连网上 ...
- Asp.net自定义控件开发任我行(3)-Render
摘要 上一篇我们讲到了自定义标签TagPrefix用法,此篇我们来讲一下控件的呈现,主要是呈现下拉框 内容 呈现的方法有,Render,RenderControl,RenderChildren,这三个 ...
- Asp.net自定义控件开发任我行(1)-笑傲江湖
1.引言 参加工作5个月了,来到一家小公司,有几只老鸟带我,但不是我公司的,几个礼拜才来一次.来到公司做的第一个项目是web项目,里面有很多的重复代码,页面代码都是千篇一律,你这人也太水了吧,垃圾代码 ...
- Asp.net自定义控件开发任我行(5)-嵌入资源上
摘要 上一篇我们讲了VitwState保存控件状态,此章我们来讲讲嵌入css文件,js文件,嵌入Image文件我也一笔带过. 内容 随着我的控件的完善,我们目标控件DropDwonCheckList最 ...
- Asp.net自定义控件开发任我行(6)-嵌入资源下
摘要 上一章,我们讲了嵌入.css文件,这一章,我们来讲一下嵌入.js文件,也顺带一个嵌入Image文件 内容 我们前面的几章,一运行,下拉框就显示出来了,但是DropDwonList的下拉框是被隐藏 ...
- Asp.net 自定义控件开发相关的几种嵌入资源解决方案
前提: 如下将要介绍的几种类型资源都要在其属性页窗口, 将 <生成操作> 属性, 设置为[嵌入的资源], 如图: ► 给自定义控件添加自定义图标的几种方案 方法一: 直接在自定义控 ...
随机推荐
- echarts的title和legend重合解决(各种小细节)
一:关于title与legend重叠 1.重合样子 2.解决办法: legend:{ show: true, top:"6%",//与上方的距离 可百分比% 可像素px }, 3. ...
- CST,CET,UTC,GMT,DST,Unix时间戳几种常见时间概述与关系(转)
转自:http://www.cnblogs.com/frontendBY/p/5215785.html 1.UTC: Universal Time Coordinated 协调世界时,又称世界标准时间 ...
- CSS变量(CSS variable)
使用 CSS 变量编写你的样式代码 基本使用: 1. --variable: <declaration-value> 2. <css-attribute>: var(--var ...
- 关于docker容器内核参数修改问题
以下内容截取自docker官方文档 地址:https://docs.docker.com/edge/engine/reference/commandline/run/#configure-namesp ...
- Windows Profile的一些问题
电脑症状:桌面复制的文件重启后消失:新安装的软件重启后也自动消失.排查:使用autoruns观察,发现安装了麦咖啡和360两套“安全”软件,除此外并无异常,任务管理器內也无异常发现.过程:1.保险起见 ...
- Handling Exceptions
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Exceptions/Tasks/Handling ...
- vuejs课程简介及框架简介
vuejs准备知识: 1.前端开发基础 html css js 2.前端模块化基础 3.对es6有初步的了解 vuejs是一种轻量级的MVM框架,他吸收了react和angular的优点,强调re ...
- 2017.12.6 计算机算法分析与设计---------Fibonacci数列
(1)题目: 无穷数列1,1,2,3,5,8,13,21,34,55,--,称为Fibonacci数列.它可以递归地定义为: 第n个Fibonacci数可递归地计算如下: int fibonacci( ...
- java web用户登录界面
做这次实验,主要用到了mysql java web 的 内容 实验代码: IUserDao.java package com.jaovo.msg.dao; import java.util.List ...
- 洛谷P3374树状数组1
下有彩蛋(from https://www.cnblogs.com/wuwangchuxin0924/p/5921130.html)树状数组的blog写的最好的是这位//https://www.cnb ...