简单的自定义控件四简单的自定义控件四
2013-01-09 10:55
369 查看
如有不明白的地方欢迎加QQ群14670545 探讨
简单的自定义控件三
在学习了控件的生命周期之后,我们来进一步处学习。这节我们把简单的js判断放到控件里面,同时对不可用的控件要禁止其提交行为。
好的,首先分析下,我怎么知道页面上那些是我自定义的控件呢,GetType()方法或者is xxx类型 都可以用来判断,但是我必须要知道GetType()之后要与哪种类型匹配,is也是一样。基于这种思考,我们就需要来一个接口(interface)以方便我们做某些功能的统一处理。
1.新建类库CustomerWebControls,新建类ICustomControl.cs,写入代码如下:
2.来一个我们来绘一个textbox,前面章节有讲到,这里就不说了,直接上代码:
)
CCTools.cs类的代码如下:
我们需要在页面上写一些css以配合效果
到此我们的重绘一个简单的TextbOX结束,下面我们来处理button按钮:
2.在CustomerWebControls类库里面新建一个类CCButton.cs,同样,我们也让它继承ICustomControl接口,达到统一标准。
还记得我们上一章讲的web服务器控件的生命周期吗,这里我们就需要用到啦。在按钮提交的时候一般我们会做一些客户端的脚本提示,不如在OnClientClick事件里面
return checkInfo();一下。这个checkInfo是个客户端的js函数,当然它是我们自己写的一些东西。这里我们不妨用一个属性来指代当前自定义的button是否需要添加一个这样的提示,这时候我们可以重写button的AddAttributesToRender事件,它是用来将控件的属性添加到输出流用以在客户端上呈现内容,这里我们就可以写一些脚本判断。
当然,当我们的按钮向服务器提交完以后,或许还要做一些提示什么的,这个时候可以对回发事件进行重写。按照上面的想法,现在我们来处理代码:
到此我们生成一下,然后web层引用,再把两个控件拖到页面上去看看
为了好看和测下事件的效果,我们添加一下属性,最终页面代码:
继承PageUI。这样做的好处事,我们可以在PageUI里面处理我自定义控件的一些事(比如权限控制,比如根据权限是否只读等等),在基类BasePage我们可以统一处理符合某一个情况下的所有控件行为(比如让所有不可用的控件全部不能做提交处理)。好了,我们来写代码:
BasePage:
PageUI:
ccPage(页面后台):
生成一些,运行效果
①效果
②按钮单击效果
③服务器回传页面跳转了,在把页面返回来刷新下看看
页面不会提示,但是当我们把
注释掉,再测试一下:先弹窗
刷新测试一下会有提示
OK,到此结束,下一节我们把客户端的js脚本放进来。做一个ui比较好的demo
简单的自定义控件三
在学习了控件的生命周期之后,我们来进一步处学习。这节我们把简单的js判断放到控件里面,同时对不可用的控件要禁止其提交行为。
好的,首先分析下,我怎么知道页面上那些是我自定义的控件呢,GetType()方法或者is xxx类型 都可以用来判断,但是我必须要知道GetType()之后要与哪种类型匹配,is也是一样。基于这种思考,我们就需要来一个接口(interface)以方便我们做某些功能的统一处理。
1.新建类库CustomerWebControls,新建类ICustomControl.cs,写入代码如下:
namespace CustomerWebControls { /// <summary> /// 自定义控件的统一接口 /// </summary> public interface ICustomControl { //... } }ICustomControl这里面我们没有写什么,空着的,后面我们会讲到比如控件的权限,到时候需要修改我们的接口(后话了),好了现在我们自定义的控件要是继承了ICustomControl接口,那么我们可以认为它属于ICustomControl类型(标准)的规格控件
2.来一个我们来绘一个textbox,前面章节有讲到,这里就不说了,直接上代码:
using System; using System.ComponentModel; using System.Web.UI; using System.Web.UI.WebControls; namespace CustomerWebControls { [DefaultProperty("IsValidata"), ToolboxData("<{0}:CCTextBox runat=server />")] public class CCTextBox : TextBox, ICustomControl { /// <summary> /// 是否验证输入的合法性 /// </summary> [Bindable(true), Category("Appearance"), DefaultValue(true), Localizable(true)]//在属性窗口中是否可见 public bool IsValidata { get { return ViewState["IsValidata"] != null ? (bool)ViewState["IsValidata"] : false; } set { ViewState["IsValidata"] = value; } } /// <summary> /// 是否移除不安全字符串 /// </summary> [Bindable(true), Category("Appearance"), DefaultValue(true), Localizable(true)] public bool IsRemoveUnsafeHtml { set { ViewState["IsRemoveUnsafeHtml"] = value; } get { return ViewState["IsRemoveUnsafeHtml"] != null ? (bool)ViewState["IsRemoveUnsafeHtml"] : true; } } /// <summary> /// 重写TextBox的Text属性 /// </summary> public override string Text { get { return IsRemoveUnsafeHtml ? CCTools.RemoveUnsafeHtml(base.Text.Trim()) : base.Text.Trim(); } set { base.Text = value; } } protected override void OnPreRender(EventArgs e) { if (string.IsNullOrEmpty(CssClass)) { CssClass = "txt"; Attributes["onmouseover"] = "this.className='colorfocus';"; Attributes["onfocus"] = "this.className='colorfocus';"; Attributes["onmouseout"] = "this.className='colorblur';"; Attributes["onblur"] = "this.className='colorblur';"; } base.OnPreRender(e); } protected override void Render(HtmlTextWriter writer) { base.Render(writer); if (IsValidata)//需要验证,就添加一个js提示 writer.Write("<span id=\"" + ClientID + "Tip\"></span>"); } } }这里的IsValidata属性我们是为了下一节把客户端脚本(比如jquery ui)加进来处理而提前写的(此篇先不说了,看下篇吧
)
CCTools.cs类的代码如下:
namespace CustomerWebControls { public class CCTools { private const string StrKeyWord = @"select|insert|delete|from|drop table|update|truncate|xp_cmdshell|exec master|netlocalgroup administrators|:|net user"; /// <summary> /// 过滤HTML中的不安全标签 /// </summary> /// <param name="content">目标字符</param> /// <returns>移除不合法的字符</returns> public static string RemoveUnsafeHtml(string content) { content = content.Replace("'", "").Replace("%", "").ToLower(); string[] arry_sql = StrKeyWord.Split('|'); foreach (string paramSQL in arry_sql) if (content.IndexOf(paramSQL) > -1) content = content.Replace(paramSQL, "$$"); return content; } } }基于这个CCTextBox的
CssClass = "txt"; Attributes["onmouseover"] = "this.className='colorfocus';"; Attributes["onfocus"] = "this.className='colorfocus';"; Attributes["onmouseout"] = "this.className='colorblur';"; Attributes["onblur"] = "this.className='colorblur';";
我们需要在页面上写一些css以配合效果
<style type="text/css"> .txt { border-top-width: 1px; padding-right: 1px; padding-left: 1px; padding-bottom: 1px; padding-top: 1px; border-left-width: 1px; border-bottom-width: 1px; border-right-width: 1px; border-left-color: #707070; border-bottom-color: #CECECE; border-top-color: #707070; border-right-color: #CECECE; font-family: Tahoma, Verdana, "宋体"; font-size: 12px; color: #000000; background-color: #FFFFFF; height:18px; line-height:18px; } .colorfocus { border-width:1px; border-style:solid; border-left-color: #069; border-bottom-color: #C2D5E3; border-top-color: #069; border-right-color: #C2D5E3; background-color: #EBF2F6; height:18px; line-height:18px; } .colorblur { border-width:1px; border-style:solid; border-left-color: #707070; border-bottom-color: #CECECE; border-top-color: #707070; border-right-color: #CECECE; background-color: #ffffff; height:18px; line-height:18px; } </style>
到此我们的重绘一个简单的TextbOX结束,下面我们来处理button按钮:
2.在CustomerWebControls类库里面新建一个类CCButton.cs,同样,我们也让它继承ICustomControl接口,达到统一标准。
还记得我们上一章讲的web服务器控件的生命周期吗,这里我们就需要用到啦。在按钮提交的时候一般我们会做一些客户端的脚本提示,不如在OnClientClick事件里面
return checkInfo();一下。这个checkInfo是个客户端的js函数,当然它是我们自己写的一些东西。这里我们不妨用一个属性来指代当前自定义的button是否需要添加一个这样的提示,这时候我们可以重写button的AddAttributesToRender事件,它是用来将控件的属性添加到输出流用以在客户端上呈现内容,这里我们就可以写一些脚本判断。
当然,当我们的按钮向服务器提交完以后,或许还要做一些提示什么的,这个时候可以对回发事件进行重写。按照上面的想法,现在我们来处理代码:
using System; using System.Collections.Generic; using System.Text; using System.Web.UI; using System.ComponentModel; using System.Web.UI.WebControls; namespace CustomerWebControls { [DefaultProperty("Text")] [ToolboxData("<{0}:CCButton runat=server></{0}:CCButton>")] public class CCButton : Button, ICustomControl { /// <summary> /// 默认的构造函数。 /// </summary> public CCButton() { base.Text = "保存"; this.ViewState["afterSubmitText"] = "提交成功"; this.ViewState["checkclient"] = false; this.ViewState["beforeSubmitText"] = "确定要提交吗?"; } /// <summary> /// 获取或设置单击按钮后,按钮上所显示的文本。 /// </summary> [Bindable(true), Category("Appearance"), DefaultValue("提交成功"), Description("指示单击提交后,按钮回发事件弹出的提示信息。")] public string AfterSubmitText { get { string afterSubmitText = (string)this.ViewState["afterSubmitText"]; if (afterSubmitText != null) { return afterSubmitText; } else { return string.Empty; } } set { this.ViewState["afterSubmitText"] = value; } } [Bindable(true), Category("Appearance"), DefaultValue(false), Description("指示是否要显示一个提示框。")] public bool CheckClient { get { return (bool)this.ViewState["checkclient"]; } set { this.ViewState["checkclient"] = value; } } [Bindable(true), Category("Appearance"), DefaultValue("确定要提交吗?"), Description("指示提示框内所包含的内容。")] public string BeforeSubmitText { get { return (string)this.ViewState["beforeSubmitText"]; } set { this.ViewState["beforeSubmitText"] = value; } } protected override void Render(HtmlTextWriter writer) { base.Render(writer); } /// <summary> /// 处理回传事件 /// </summary> /// <param name="eventArgument"></param> protected override void RaisePostBackEvent(string eventArgument) { Alert(AfterSubmitText); base.RaisePostBackEvent(eventArgument); } /// <summary> /// 控件的属性添加到输出流用以在客户端上呈现内容 /// <remarks>重写button按钮的AddAttributesToRender</remarks> /// </summary> /// <param name="writer">HtmlTextWriter:其中包含要在客户端上呈现内容的输出流</param> protected override void AddAttributesToRender(HtmlTextWriter writer) { System.Text.StringBuilder ClientSideEventReference = new System.Text.StringBuilder(); if (((this.Page != null) && this.CausesValidation) && (this.Page.Validators.Count > 0)) ClientSideEventReference.Append("if (typeof(Page_ClientValidate) == 'function'){if (Page_ClientValidate() == false){return false;}}"); if (this.CheckClient) ClientSideEventReference.Append("if (!confirm('" + this.BeforeSubmitText + "')){return false}"); ClientSideEventReference.Append("this.disabled = true;"); ClientSideEventReference.Append(this.Page.ClientScript.GetPostBackEventReference(this, string.Empty)); writer.AddAttribute(HtmlTextWriterAttribute.Onclick, ClientSideEventReference.ToString(), true); base.AddAttributesToRender(writer); } /// <summary> /// 在客户端显示弹出对话框。 /// </summary> /// <param name="msg">要显示的信息。</param> public void Alert(string msg) { Alert("alert", msg); } /// <summary> /// 在客户端显示弹出对话框。 /// </summary> /// <param name="name">脚本块标识。当同一页面要调用两个弹出框时需不同的标识,否则后者会覆盖前者。</param> /// <param name="msg">要显示的信息。</param> public void Alert(string name, string msg) { Page.ClientScript.RegisterClientScriptBlock(this.GetType(), name, "<script language=\"javascript\">alert('" + msg + "');</script>"); } } }
到此我们生成一下,然后web层引用,再把两个控件拖到页面上去看看
<cc1:CCTextBox ID="CCTextBox1" runat="server" ></cc1:CCTextBox> <cc1:CCButton ID="CCButton1" runat="server" />
为了好看和测下事件的效果,我们添加一下属性,最终页面代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ccPage.aspx.cs" Inherits="MyWebSiteTest.Manager.ccPage" %>我们在后台做个简单的btnTest_Click事件,为什么要添加这个事件,因为我们需要测试防止页面刷新之后重复提交,等会你就看到效果了,刷新页面(如果页面不跳转,这时候刷新还是会提示的,因为页面重绘了,跳转之后返回来刷新时不会提示的)也不会提交的。
<%@ Register Assembly="CustomerWebControls" Namespace="CustomerWebControls" TagPrefix="cc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>测试封装的控件</title>
<style type="text/css"> .txt { border-top-width: 1px; padding-right: 1px; padding-left: 1px; padding-bottom: 1px; padding-top: 1px; border-left-width: 1px; border-bottom-width: 1px; border-right-width: 1px; border-left-color: #707070; border-bottom-color: #CECECE; border-top-color: #707070; border-right-color: #CECECE; font-family: Tahoma, Verdana, "宋体"; font-size: 12px; color: #000000; background-color: #FFFFFF; height:18px; line-height:18px; } .colorfocus { border-width:1px; border-style:solid; border-left-color: #069; border-bottom-color: #C2D5E3; border-top-color: #069; border-right-color: #C2D5E3; background-color: #EBF2F6; height:18px; line-height:18px; } .colorblur { border-width:1px; border-style:solid; border-left-color: #707070; border-bottom-color: #CECECE; border-top-color: #707070; border-right-color: #CECECE; background-color: #ffffff; height:18px; line-height:18px; } </style>
</head>
<body>
<form id="form1" runat="server">
<div style=" margin:0 auto; width:600px;">
<cc1:CCTextBox ID="CCTextBox1" runat="server" Width="200" IsValidata="true" ></cc1:CCTextBox>
<cc1:CCButton ID="CCButton1" runat="server" CheckClient="true" OnClick="btnTest_Click" />
</div>
</form>
</body>
</html>
protected void btnTest_Click(object sender, EventArgs e) { Response.Redirect("http://www.baidu.com"); }好了,基本已经完成,但是我们一开始说了,对于那些失效的按钮,我们要保证它不能提交事件的(比如winform软件,某些按钮是失效的,我们可以用一些外挂插件让失效的按钮的可用,完全是可以做到),为了以防万一我们需要做这样的处理。同时,我们也说了,我怎么获取页面上我自己写的ICustomControl标准接口的控件呢,基于这些考虑,我们需要些2个基类,一个最终的BasePage(它继承于System.Web.UI.Page),一个中间层的PageUI(它继承于BasePage),我们再让页面类的ccPage.cs
继承PageUI。这样做的好处事,我们可以在PageUI里面处理我自定义控件的一些事(比如权限控制,比如根据权限是否只读等等),在基类BasePage我们可以统一处理符合某一个情况下的所有控件行为(比如让所有不可用的控件全部不能做提交处理)。好了,我们来写代码:
BasePage:
using System.Web.UI; namespace MyWebSiteTest { public class BasePage : System.Web.UI.Page { /// <summary> /// 禁止客户端失效按钮提交 /// <remarks>RaisePostBackEvent通知引起回发的服务器控件:它应处理传入的回发事件</remarks> /// </summary> protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument) { if (!(bool)sourceControl.GetType().GetProperty("Enabled").GetValue(sourceControl, null)) return; base.RaisePostBackEvent(sourceControl, eventArgument); } } }
PageUI:
using System; using System.Collections.Generic; using System.Web.UI; using CustomerWebControls;//我们自定义控件的类库 namespace MyWebSiteTest { public class PageUI : BasePage { /// <summary> /// 控件列表 /// </summary> private readonly List<Control> _CustomControl; /// <summary> /// 构造 /// </summary> public PageUI() { _CustomControl = new List<Control>(); } /// <summary> /// 获取自定义服务器控件 /// </summary> /// <param name="cc"></param> private void GetCustomServerButtons(ControlCollection cc) { foreach (Control c in cc) { if (c is ICustomControl) _CustomControl.Add(c); else if (c.HasControls()) GetCustomServerButtons(c.Controls);//调用自身(伪递归) } } /// <summary> /// 做一些处理咯 /// <remarks>可自由发挥处理,比如权限方面的处理</remarks> /// </summary> private void InitControlsRight() { foreach (Control obj in _CustomControl) { switch (obj.GetType().Name) { case "CCTextBox": CCTextBox cctextbox = obj as CCTextBox; if (cctextbox != null && cctextbox.Enabled) cctextbox.ReadOnly = false; break; } } } /// <summary> /// 在页初始化后引发 /// </summary> protected override void OnInitComplete(EventArgs e) { base.OnInitComplete(e); GetCustomServerButtons(Controls); InitControlsRight(); } } }
ccPage(页面后台):
using System; namespace MyWebSiteTest.Manager { public partial class ccPage : PageUI { protected void Page_Load(object sender, EventArgs e) { } protected void btnTest_Click(object sender, EventArgs e) { Response.Redirect("http://www.baidu.com"); } } }
生成一些,运行效果
①效果
②按钮单击效果
③服务器回传页面跳转了,在把页面返回来刷新下看看
页面不会提示,但是当我们把
//Response.Redirect("http://www.baidu.com");
注释掉,再测试一下:先弹窗
刷新测试一下会有提示
OK,到此结束,下一节我们把客户端的js脚本放进来。做一个ui比较好的demo
相关文章推荐
- 第一章 .Net 控件开发(WebForm) 开发简单自定义控件(6) 自定义Style类
- Android自定义控件系列 十:利用添加自定义布局来搞定触摸事件的分发,解决组合界面中特定控件响应特定方向的事件
- Android-自定义控件之重写控件(自定义TextView)
- Asp.net 2.0 自定义控件开发[创建自定义浮动菜单FloadMenu控件][示例代码下载]
- Asp.net 2.0 自定义控件开发[创建自定义HeaderRow的GridView控件][示例代码下载]
- 自定义控件系列之应用篇——自定义标题栏控件
- Asp.net 2.0 自定义控件开发[创建自定义浮动菜单FloadMenu控件][示例代码下载]
- Asp.net 2.0 自定义控件开发[创建自定义右键PopupMenu控件][示例代码下载]
- Asp.net 2.0 自定义控件开发[创建自定义浮动菜单FloadMenu控件][示例代码下载]
- Asp.net 2.0 自定义控件开发[创建自定义浮动菜单FloadMenu控件][示例代码下载]
- 使用jQuery和CSS自定义HTML5 Video 控件 简单适用
- Android自定义控件系列 十:利用添加自定义布局来搞定触摸事件的分发,解决组合界面中特定控件响应特定方向的事件
- 最简单的自定义ViewGroup布局控件
- IOS自定义日历控件的简单实现(附思想及过程)
- 用于简单自定义gridview控件
- 自定义View简单案例-自绘控件
- Android自定义控件之自定义组合控件(三)
- Android自定义控件---组合控件(包括自定义属性)
- 自定义Gridview用户控件,简单实用,希望大家多提宝贵意见
- 自定义控件起步(一)(简单的自定义view)