您的位置:首页 > 编程语言 > ASP

创建ASP.NET WEB自定义控件

2009-05-14 15:04 381 查看
WEB自定义控件编程是ASP.NET编程里面比较难的一部分,尤其是复杂的控件需要用到平常不常用的一些技术技巧。

下面根据一些我自己的实践经验,向读者介绍一下这方面的技术。
简单的继承控件:ConfirmButton
我们在用ASP.NET编写应用程序的时候,经常需要在按钮提交的时候弹出一个[OK][Cancel]的确认框,以防止用户在操作的时候误提交。实现这个功能传统的方法是在代码页的Page_Load事件里添加按钮的Attributes,但是每个按钮都要添加一遍比较麻烦。下面我们来自己制作一个有这样功能的按钮解决这个问题。
(例程采用C#语言)
1.新建项目
首先打开Visual Studio.net,建立一个新的Web控件库项目,取名TestLib。在解决方案资源管理器里会有一个标识为WebCustomControl1.cs的源代码文件,将其改名为ConfirmButton.cs。
2.编辑代码
打开ConfirmButton.cs源文件,将类名“WebCustomControl1”改为“ConfirmButton”;将类继承自“System.Web.UI.WebControls.WebControl”改为“System.Web.UI.WebControls.Button”;
将代码“[DefaultProperty("Text"),
ToolboxData("<{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")]”
改为“[DefaultProperty("Text"),
ToolboxData("<{0}:ConfirmButton runat=server></{0}:ConfirmButton>")]”,这样使得aspx页面显示的该控件xml代码标识显示“<cc1:ConfirmButton …> …</cc1: ConfirmButton>”。
下面进一步修改代码,删除原有代码:
private string text;
[Bindable(true),
Category("Appearance"),
DefaultValue("")]
public string Text
{
get
{
return text;
}
set
{
text = value;
}
}
添加新代码(用于设置在弹出的确认框中显示的信息):
private string _confirmMessage = "Is OK?";
[Bindable(true),
Category("Appearance"),
DefaultValue("Is OK?")]
public string ConfirmMessage
{
get
{
return _confirmMessage;
}
set
{
_confirmMessage = value;
}
}
最后将
protected override void Render(HtmlTextWriter output)
{
output.Write(Text);
}
改为protected override void Render(HtmlTextWriter output)
{
base.Attributes.Add("OnClick","return confirm('"+this._confirmMessage+"');");
base.Render(output);
}
3.添加在工具箱中显示的图标
选择菜单[项目]/[添加新项],在弹出的对话框中选择创建“位图文件”并将文件名改为“ConfirmButton”(很重要,位图文件名必需和类名一致)。然后在“解决方案资源管理器”中选中该位图文件,并在属性设置框中将“生成操作”的值设置为“嵌入的资源”。

好了,编译一下吧,一切OK了。剩下的事,就是把编译好的dll文件找到并添加到工具箱中,在以后的WEB应用程序中就可以用了。

(二)

本文通过一段完整的代码向读者介绍复合自定义控件的制作,包括:自定义属性、事件处理、控件间数据传递等方面的技术。

以下是一个登陆框的代码,包括:用户名输入TextBox、密码输入TextBox、提交Button、重置Button以及承载以上四项的Panel。控件类名为LoginCtrl。
(例程使用C#)
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Drawing;

namespace TestLib
{
[DefaultProperty("BackColor"),
ToolboxData("<{0}:LoginCtrl runat=server></{0}:LoginCtrl>")]
public class LoginCtrl : System.Web.UI.WebControls.WebControl
{
private Color _fontColor = Color.Black;//声明字体颜色变量
private Color _backColor = Color.White;//声明控件背景变量
首先声明要在复合控件中使用的子控件。
private Label lblUserName = new Label();//显示“用户名”的Label控件
private Label lblPassWord = new Label();//显示“密码”的Label控件
private TextBox txtUserName = new TextBox();//用户名输入的TextBox控件
private TextBox txtPassWord = new TextBox();//密码输入的TextBox控件
private Button submitButton = new Button();//提交Button控件
private Button clearButton = new Button();//重置Button控件
private System.Web.UI.WebControls.Panel pnlFrame = new System.Web.UI.WebControls.Panel();//承载其它控件的容器Panel控件
当然要在符合控件中使用的事件一定要声明的,它们会出现在属性框的事件栏里。
public event EventHandler SubmitOnClick;//声明自定义控件LoginCtrl的提交事件
public event EventHandler ClearOnClick;//声明自定义控件LoginCtrl的重置事件

public LoginCtrl()
{
刚刚声明的子控件和事件要在这里进行初始化处理。
//初始化控件的属性
this.lblUserName.Text = "用户名:";
this.lblPassWord.Text = "密 码:";
this.txtPassWord.TextMode = System.Web.UI.WebControls.TextBoxMode.Password;

this.pnlFrame.Width = 240;
this.pnlFrame.Height = 120;
this.pnlFrame.BackColor = Color.Empty;
//添加提交按钮点击事件
submitButton.Text = "确定";
submitButton.Click += new EventHandler(this.SubmitBtn_Click);
//添加重置按钮点击事件
clearButton.Text = "重置";
clearButton.Click += new EventHandler(this.ClearBtn_Click);
//将声明的各子控件添加到LoginCtrl中
this.Controls.Add(this.submitButton);
this.Controls.Add(this.clearButton);
this.Controls.Add(this.txtUserName);
this.Controls.Add(this.txtPassWord);
this.Controls.Add(this.lblUserName);
this.Controls.Add(this.lblPassWord);
this.Controls.Add(this.pnlFrame);
}
根据自己的需要添加或重载符合控件的公共属性
//字体颜色属性
[Bindable(false),
Category("Appearance"),
DefaultValue("")]
public override Color ForeColor
{
get
{
return this._fontColor;
}
set
{
this._fontColor = value;
}
}
//控件背景属性
[Bindable(false),
Category("Appearance"),
DefaultValue("")]
public override Color BackColor
{
get
{
return this._backColor;
}

set
{
this._backColor = value;
}
}
//用户名属性
[Bindable(false),
Category("Appearance"),
DefaultValue("")]
public string UserName
{
get
{
return this.txtUserName.Text;
}
set
{
this.txtUserName.Text = value;
}
}
//密码属性
[Bindable(false),
Category("Appearance"),
DefaultValue(""), Browsable(false)]
public string PassWord
{
get
{
return this.txtPassWord.Text;
}
set
{
this.txtPassWord.Text = value;
}
}
//控件宽度属性
[Bindable(false),
Category("Appearance"),
DefaultValue("")]
public override Unit Width
{
get
{
return this.pnlFrame.Width;
}
set
{
this.pnlFrame.Width = value;
}
}
//控件高度属性
[Bindable(false),
Category("Appearance"),
DefaultValue("")]
public override Unit Height
{
get
{
return this.pnlFrame.Height;
}
set
{
this.pnlFrame.Height = value;
}
}
//控件边框颜色属性
[Bindable(false),
Category("Appearance"),
DefaultValue("")]
public override Color BorderColor
{
get
{
return this.pnlFrame.BorderColor;
}
set
{
this.pnlFrame.BorderColor = value;
}
}
//控件边框样式属性
[Bindable(false),
Category("Appearance"),
DefaultValue("")]
public override BorderStyle BorderStyle
{
get
{
return this.pnlFrame.BorderStyle;
}
set
{
this.pnlFrame.BorderStyle = value;
}
}
//控件边框宽度属性
[Bindable(false),
Category("Appearance"),
DefaultValue("")]
public override Unit BorderWidth
{
get
{
return this.pnlFrame.BorderWidth;
}
set
{
this.pnlFrame.BorderWidth = value;
}
}
下面要把控件输出出去,展示在页面上。
/// <summary>
/// 将此控件呈现给指定的输出参数。
/// </summary>
/// <param name="output"> 要写出到的 HTML 编写器 </param>
protected override void Render(HtmlTextWriter output)
{
this.pnlFrame.RenderBeginTag(output);//输出Panel控件

//在Panel中绘制表格
output.AddAttribute(HtmlTextWriterAttribute.Border,"0");
output.AddAttribute(HtmlTextWriterAttribute.Cellpadding,"0");
output.AddAttribute(HtmlTextWriterAttribute.Cellspacing,"0");
output.AddAttribute(System.Web.UI.HtmlTextWriterAttribute.Width,"100%");
output.AddAttribute(System.Web.UI.HtmlTextWriterAttribute.Height,"100%");
output.AddAttribute(HtmlTextWriterAttribute.Bgcolor,this._backColor.Name);
output.RenderBeginTag(HtmlTextWriterTag.Table);

output.RenderBeginTag(HtmlTextWriterTag.Tr);
output.RenderBeginTag(HtmlTextWriterTag.Td);
//在表格中添加Label控件
this.lblUserName.ForeColor = this._fontColor;
this.lblUserName.RenderControl(output);
output.RenderEndTag();
output.RenderBeginTag(HtmlTextWriterTag.Td);
//在表格中添加TextBox控件
this.txtUserName.RenderControl(output);
output.RenderEndTag();
output.RenderEndTag();
output.RenderBeginTag(HtmlTextWriterTag.Tr);
output.RenderBeginTag(HtmlTextWriterTag.Td);
//在表格中添加Label控件
this.lblPassWord.ForeColor = this._fontColor;
this.lblPassWord.RenderControl(output);
output.RenderEndTag();
output.RenderBeginTag(HtmlTextWriterTag.Td);
//在表格中添加TextBox控件
this.txtPassWord.RenderControl(output);
output.RenderEndTag();
output.RenderEndTag();
output.RenderBeginTag(HtmlTextWriterTag.Tr);
output.AddAttribute(HtmlTextWriterAttribute.Align,"right");
output.RenderBeginTag(HtmlTextWriterTag.Td);
//在表格中添加Button控件
this.submitButton.RenderControl(output);
output.RenderEndTag();
output.AddAttribute(HtmlTextWriterAttribute.Align,"center");
output.RenderBeginTag(HtmlTextWriterTag.Td);
//在表格中添加Button控件
this.clearButton.RenderControl(output);
output.RenderEndTag();
output.RenderEndTag();

output.RenderEndTag();

this.pnlFrame.RenderEndTag(output);
}
当按钮点击时怎么做呢?这是个事件冒泡。
//处理提交按钮点击事件
private void SubmitBtn_Click(object sender, EventArgs e)
{
EventArgs e1 = new EventArgs();
if(this.SubmitOnClick!=null)
this.SubmitOnClick(this.submitButton,e1);
}
//处理重置按钮点击事件
private void ClearBtn_Click(object sender, EventArgs e)
{
this.txtPassWord.Text = "";
this.txtUserName.Text = "";
EventArgs e1 = new EventArgs();
if(this.ClearOnClick!=null)
this.ClearOnClick(this.clearButton,e1);
}
}
}
编译一下,OK!
这个控件没有什么实际的使用价值,本文制作这个例子是为了向读者展示复合控件的制作方法,也很简单,是吧?

(三)

本系列文章中“例程1”和“例程2”讲述了利用Visual Studio.NET2003中已有的WEB自定义控件,通过继承或复合一些简单控件生成自己需要的自定义控件。这样的控件制作比较简单,但是它的执行效率相对要低一些,所以如果我们不继承已有的控件那么这个控件该怎么做呢?
下面作者通过实例向大家讲述这种自写控件的编程方法。
(例程使用C#)
本例程实现一个TextBox,该TextBox对于输入的字符串进行检验,将半角单引号替换为全角单引号(半角单引号导致数据库错误)。
控件首先要继承所有控件的基类:System.Web.UI.Control,实现两个接口:IStateManager(实现ViewState),IPostBackDataHandler(处理回发数据),然后可以仿照System.Web.UI.WebControls.TextBox编写一些常用的属性和方法。因篇幅限制,本例只实现Text属性。
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;

namespace Demo
{
/// <summary>
/// WebCustomControl1 的摘要说明。
/// </summary>
像前两个例子一样,先处理一下控件设计时属性。
[DefaultProperty("Text"),
ToolboxData("<{0}:DemoTextBox runat=server></{0}:DemoTextBox>")]
public class DemoTextBox : System.Web.UI.Control,IStateManager,IPostBackDataHandler
{
private StateBag _state;
private bool _marked;

下面就是我们要实现的属性:Text
[Bindable(true),
Category("Appearance"),
DefaultValue("")]
public string Text
{
get
{
string _text = (string) ViewState["Text"];
return _text==null?"":_text;
}

set
{
string text = "";
text = value;
text = text.Replace("'","’");
ViewState["Text"] = text;
}
}
为了能实现视图状态就必须实现IStateManager接口
object IStateManager.SaveViewState()
{
object _stateState = null;
if( _state != null )
_stateState = ((IStateManager)_state).SaveViewState();

if ( _stateState == null )
return null;

return _stateState;
}

void IStateManager.TrackViewState()
{
_marked = true;

if( _state != null )
((IStateManager)_state).TrackViewState();
}

void IStateManager.LoadViewState( object state )
{
if( state != null )
{
object _newState = (object)state;

((IStateManager)ViewState).LoadViewState( _newState );
}
}

bool IStateManager.IsTrackingViewState
{
get
{
return _marked;
}
}

internal new StateBag ViewState //注意,这里覆盖基类的ViewState属性
{
get
{
if( _state == null )
{
_state = new StateBag( true );
if( ((IStateManager)this).IsTrackingViewState )
((IStateManager)_state).TrackViewState();
}
return _state;
}
}

下面把控件的表现输出到页面,其实System.Web.UI.WebControls.TextBox也是重新包装了Input而已。
protected override void Render(HtmlTextWriter output)
{
string strOutput = "<Input name=/""+this.ClientID+"/" type=/"text/" value=/""+this.Text+"/">";
output.Write(strOutput);
}
#region IPostBackDataHandler 成员

public void RaisePostDataChangedEvent()
{
// TODO: 添加 DemoTextBox.RaisePostDataChangedEvent 实现
}
下面的方法很重要,把回发的数据保存。
public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
{
// TODO: 添加 DemoTextBox.LoadPostData 实现
string presentValue = this.Text;
string postedValue = postCollection[postDataKey];

if (!presentValue.Equals(postedValue))//如果回发数据不等于原有数据
{
this.Text = postedValue;
return true;
}
return false;
}

#endregion
}
}

好了,一个自己写的TextBox控件完成了,现在把编译好的dll文件找到并添加到工具箱中就可以拖放到页面上了。本例实现的ViewState处理是一个演示,帮助大家了解自己实现ViewState的方法,继承的Control类已经实现了该处理,实际中只需要实现IPostBackDataHandler就可以了,ViewState的问题控件自己就解决了。
控件生成,但是当拖放到页面上的时候它的设计时的显示不太友好,只是一串文字。那么如何像System.Web.UI.WebControls.TextBox那样拖上去后显示为一个输入框呢?
下面我为读者介绍改变显示的方法。
首先在控件项目中添加一个类文件,命名为:Designer.cs。然后修改为如下代码:
using System;
using System.Web.UI.Design;
using System.ComponentModel;

namespace Demo
{
/// <summary>
/// Designer 的摘要说明。
/// </summary>
public class DemoDesigner : ControlDesigner//继承ControlDesigner类
{
private DemoTextBox demoTextBox;//声明一个控件类对象

public override void Initialize(IComponent component)
{
this.demoTextBox = (DemoTextBox)component;
base.Initialize(component);
}
//重载函数GetDesignTimeHtml()
public override string GetDesignTimeHtml()
{
string _html = "";
_html = "<Input type=/"text/" value="+this.demoTextBox.Text+">";
return _html;
}
}
}
设计器完成了,但是还不能使控件拥有设计时显示,还要在控件类的属性代码中添加Designer("Demo.DemoDesigner"),使控件和设计器关联。属性代码如下所示:
[DefaultProperty("Text"),
Designer("Demo.DemoDesigner"),
ToolboxData("<{0}:DemoTextBox runat=server></{0}:DemoTextBox>")]

现在这个控件基本完成了,编译后再拖到页面上你会发现显示的样子与TextBox一样了。
以这个代码为框架,读者可以按自己的需要扩展控件的属性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: