2004-10-24+ 自定义事件(事件处理+综合实例:模仿Repeater)

using System;
using System.Web.UI;
using System.ComponentModel;
using System.Collections;
using System.Data;
using System.Web.UI.WebControls;

namespace CC
{
/// <summary>
/// 模仿Repeater的简单控件
/// </summary>
[ParseChildren(true), PersistChildren(false),DefaultEvent("RedItemCommand")]
public class RedRepeater: Control,INamingContainer
{
#region 模板的定义

//元素模板
private ITemplate itemTemplate;

[TemplateContainer(typeof(RedContainer)),Browsable(false),DefaultValue(null),
PersistenceMode(PersistenceMode.InnerProperty),Description("元素模板"),DefaultValue(null)]
public ITemplate ItemTemplate
{
get{ return this.itemTemplate; }
set{ this.itemTemplate=value; }
}

//头模板
private ITemplate headerTemplate;

[TemplateContainer(typeof(RedContainer)),Browsable(false),DefaultValue(null),
PersistenceMode(PersistenceMode.InnerProperty),Description("头模板"),DefaultValue(null)]
public ITemplate HeaderTemplate
{
get{ return this.headerTemplate; }
set{ this.headerTemplate=value; }
}

//脚注模板
private ITemplate footerTemplate;

[TemplateContainer(typeof(RedContainer)),Browsable(false),DefaultValue(null),
PersistenceMode(PersistenceMode.InnerProperty),Description("脚注模板"),DefaultValue(null)]
public ITemplate FooterTemplate
{
get{ return this.footerTemplate; }
set{ this.footerTemplate=value; }
}

#endregion

#region 数据源

//数据源
private object dataSource;

[Browsable(false),DefaultValue(null)]
public object DataSource
{
get{ return this.dataSource; }
set{ this.dataSource=value; }
}

#endregion

#region 重写

/// <summary>
/// 创建子控件,在这里创建的只是空壳,其内容根据ViewState来填充
/// </summary>
protected override void CreateChildControls()
{
this.Controls.Clear();
this.createControlHierarchy(false);
this.ClearChildViewState();
}

/// <summary>
/// 当用户端调用DataBind,则表示准备好了数据源,此时可以开始创建子模板
/// </summary>
/// <param name="e"></param>
protected override void OnDataBinding(EventArgs e)
{
base.OnDataBinding(e);
this.Controls.Clear();
this.ClearChildViewState();
this.createControlHierarchy(true);
}

#endregion

#region 辅助方法

/// <summary>
/// 根据是否使用DataSource创建元素模板
/// </summary>
/// <param name="useDataSource">是否使用DataSource</param>
private void createControlHierarchy(bool useDataSource)
{
//添加头模板
if(this.headerTemplate!=null)
{
RedContainer rc=new RedContainer(null);
this.headerTemplate.InstantiateIn(rc);
this.Controls.AddAt(0,rc);
}

//作为创建元素模板的数据源
IEnumerator data;

//根据用户是否使用自己的数据源来给data赋值
if(useDataSource)
{
data=this.getIEnumerator(this.dataSource);
}
else
{
int count=(int)this.ViewState["itemCount"]-1;
IEnumerable nullArray=new object[count];
data=nullArray.GetEnumerator();
}

//创建元素模板
if(this.itemTemplate!=null)
{
//计算创建了多少子模板
int itemCount=1;

while(data.MoveNext())
{
RedContainer rc=new RedContainer(data.Current);
this.itemTemplate.InstantiateIn(rc);
this.Controls.Add(rc);
itemCount++;
}

//保存数量到ViewState
this.ViewState["itemCount"]=itemCount;

//确认子模板创建完毕
this.ChildControlsCreated=true;

}

//添加脚注模板
if(this.footerTemplate!=null)
{
RedContainer rc=new RedContainer(null);
this.footerTemplate.InstantiateIn(rc);
this.Controls.AddAt(this.Controls.Count,rc);
}

}

/// <summary>
/// 得到数据源的IEnumerator形式
/// </summary>
/// <param name="source">数据源</param>
/// <returns>IEnumerator接口化的数据源</returns>
private IEnumerator getIEnumerator(object source)
{
IEnumerable data;

if(source is IEnumerable)
data=(IEnumerable)source;
else if(source is IList)
data=(IEnumerable)source;
else if(source is DataSet)
data=(IEnumerable)(((DataSet)source).Tables[0].DefaultView);
else if (source is DataTable)
data=(IEnumerable)(((DataTable)source).DefaultView);
else
data=null;

return data.GetEnumerator();
}

#endregion

#region 事件处理

//委托中使用CommandEventArgs,这样才可以获得按钮事件的丰富信息
public delegate void RedItemCommandHandler(object sender,CommandEventArgs e);

[Description("处理模板中按钮的单击事件"),Category("事件")]
public event RedItemCommandHandler RedItemCommand;

/// <summary>
/// 截获模板中的CommandEventArgs,发布自己的事件RedItemCommand
/// </summary>
/// <param name="source">事件源,按照我们在RedContainer的定义,这里应该是容器控件</param>
/// <param name="args">包含事件数据的 EventArgs 对象。</param>
/// <returns>true 在这里取消事件</returns>
protected override bool OnBubbleEvent(object source, EventArgs args)
{
if(args is CommandEventArgs)
if(this.RedItemCommand!=null)
{
CommandEventArgs e=(CommandEventArgs)args;
this.RedItemCommand(this,e);
}
return true;
}

#endregion

#region 容器控件类

/// <summary>
/// 容器控件,用来存放模板
/// 提供了索引器,这样就不用使用必须要使用反射来获得数据源信息的DataBinder.Eval方法,节省了资源
/// </summary>
public class RedContainer : WebControl,INamingContainer
{
private object dataItem;

public object DataItem
{
get{ return this.dataItem; }
}

public RedContainer(object dataItem)
{
this.dataItem=dataItem;
}

#region 索引器

//字段名索引器
public string this[string index]
{
get
{
string item;
if(this.dataItem is IDataReader)
item=((IDataRecord)dataItem)[index].ToString();
else if(this.dataItem is DataRowView)
item=((DataRowView)dataItem)[index].ToString();
else
item=string.Empty;
return item;
}

}

//序号索引器
public string this[int index]
{
get
{
string item;
if(this.dataItem is IDataReader)
item=((IDataReader)dataItem)[index].ToString();
else if(this.dataItem is DataRowView)
item=((DataRowView)dataItem)[index].ToString();
else
item=string.Empty;
return item;
}
}

#endregion

#region 事件处理
/// <summary>
/// 确定服务器控件的事件是否沿页的 UI 服务器控件层次结构向上传递。
/// </summary>
/// <param name="source">事件源,在这里就是指引发事件的按钮</param>
/// <param name="args">包含事件数据的 EventArgs 对象</param>
/// <returns>如果事件已被取消,则为 true,否则为 false。默认为 false</returns>
protected override bool OnBubbleEvent(object source, EventArgs args)
{
//如果是按钮事件,则将该事件向上传递,将容器本身做为事件源传过去,也可以选择传递按钮本身
if(args is CommandEventArgs)
this.RaiseBubbleEvent(this,args);
return true;
}
#endregion

}

#endregion
}

}

 

posted on 2006-07-03 18:42  Notus|南色的风  阅读(368)  评论(0编辑  收藏  举报