一起谈.NET技术,asp.net控件开发基础(17)
2011-09-01 23:47
821 查看
本篇将开始介绍如自定义数据绑定控件,这里感谢很多人的支持,有你们的支持很高兴。这里首先需要大家熟悉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点,还需要根据具体需求来定.但一个完成的控件是需要的。
二.为数据控件做好准备
这次的demo为不完整的Datalist控件,来源还是MSDN的例子,我们命名为TemplatedList,此控件未定义ItemCollection集合,好了,根据上面的分析我们先为TemplatedList提供项和委托及为事件提供数据的几个EventArgs,请看下面类图
//获取上次选中项
int oldSelectedIndex = SelectedIndex;
ViewState["SelectedIndex"] = value;
当第一次更改SelectedIndex属性时只执行下列代码([b]将此项标记为选中项),因为初始化时的没有oldSelectedIndex,不需要恢复样式
//第一次执行此项,并一直执行
if ((value != -1) && (table.Rows.Count > value))
//控件执行绑定时执行
public override void DataBind()
{
CreateItem方法辅助用于创建项模板,此处注意事件触发顺序,上面已经提到过。此方法根据项索引创建控件中不同的Item项 ,ViewState["ItemCount"]表示项的数量,第一次触发时或者重新执行DataBind方法时方法参数为true,并在初始化以后(回发期间)CreateChildControls方法会调用此方法,其参数为false。数据源不再是实际的数据源,而是新定义的DummyDataSource,其主要实现了一个迭代
原因很明显,为了减少对数据源的访问,所以我们平时操作数据的时候,必须重新执行DataBind方法,原因就在此。好了,到了这里差不多主要的事情我们已经完成.接着把剩下的也完成
3.呈现
又到了Render方法这里了,此方法体只要执行了PrepareControlHierarchy方法,不同的方法做不同的事情,CreateControlHierarchy方法根据索引值指定了不同的项,PrepareControlHierarchy则为不同项呈现不同的样式效果
终于差不多了,经过这么多步骤,我们终于完成了,让我们来使用控件,看一下效果
又完成一个并不完美的控件,本来还该继续下去的,怕篇幅太大,到这里还没结束,只是刚开始,下次我们继续
一.回顾
如果你使用过asp.net内置的数据控件(如DataList,Repeater),你一定会这么做
1.设置数据源 DataSource属性
2.调用数据绑定 DataBind方法
3.在控件的不同模板内使用绑定语法显示数据
这三步应该是必须要做的
其他更多的
你可能需要对绑定的数据进行统一的一些操作(如时间格式化),或者对数据的某一项进行操作(对某一项进行格式化),或者需要触发模板控件内的一些事件(如databound事件)。
根据上面的一些需求,我们需要这样做
1.对绑定的数据进行统一的一些操作: 为数据绑定控件定义Item项(表示列表的一条数据, 如Repeater的RepeaterItem)
2.对数据的某一项进行操作: 因为定义了Item项,那你肯定需要一个ItemCollection集合,其可以方便的为你检索数据
3.因为定义了RepeaterItem,原先的EventArgs和CommandEventArgs已经无法满足需求,我们需要自定义委托及其一个为控件提供数据的的ItemEventArgs
上面三点有些并非必须定义,如第2点,还需要根据具体需求来定.但一个完成的控件是需要的。
二.为数据控件做好准备
这次的demo为不完整的Datalist控件,来源还是MSDN的例子,我们命名为TemplatedList,此控件未定义ItemCollection集合,好了,根据上面的分析我们先为TemplatedList提供项和委托及为事件提供数据的几个EventArgs,请看下面类图
//获取上次选中项
int oldSelectedIndex = SelectedIndex;
ViewState["SelectedIndex"] = value;
当第一次更改SelectedIndex属性时只执行下列代码([b]将此项标记为选中项),因为初始化时的没有oldSelectedIndex,不需要恢复样式
//第一次执行此项,并一直执行
if ((value != -1) && (table.Rows.Count > value))
//控件执行绑定时执行
public override void DataBind()
{
/// <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); }
终于差不多了,经过这么多步骤,我们终于完成了,让我们来使用控件,看一下效果
又完成一个并不完美的控件,本来还该继续下去的,怕篇幅太大,到这里还没结束,只是刚开始,下次我们继续
相关文章推荐
- 一起谈.NET技术,asp.net控件开发基础(18)
- 一起谈.NET技术,asp.net控件开发基础(3)
- 一起谈.NET技术,asp.net控件开发基础(13)
- 一起谈.NET技术,asp.net控件开发基础(14)
- 一起谈.NET技术,asp.net控件开发基础(21)
- 一起谈.NET技术,asp.net控件开发基础(20)
- 一起谈.NET技术,asp.net控件开发基础(2)
- 一起谈.NET技术,asp.net控件开发基础(16)
- 一起谈.NET技术,asp.net控件开发基础(19)
- 一起谈.NET技术,asp.net控件开发基础(12)
- 一起谈.NET技术,asp.net控件开发基础(11)
- 一起谈.NET技术,asp.net控件开发基础(1)
- 一起谈.NET技术,asp.net控件开发基础(10)
- 一起谈.NET技术,asp.net控件开发基础(23)
- 一起谈.NET技术,asp.net控件开发基础(9)
- 一起谈.NET技术,asp.net控件开发基础(8)
- 一起谈.NET技术,asp.net控件开发基础(7)
- 一起谈.NET技术,asp.net控件开发基础(6)
- 一起谈.NET技术,asp.net控件开发基础(22)
- 一起谈.NET技术,asp.net控件开发基础(5)