Asp.net自定义控件系列(一)
最近看到公司某个网站中用到了自定义控件,咋一眼看去,不明白什么玩意,
网上一搜,好像确实不是几句话就能写出强大的自定义控件。好吧,作为一个码农,我决定从基本学起,写一个关于自定义控件学习过程系列。
当然了,我只是学习这个系列,不是作为一个master来出书写教程了。
如果你觉得自己是个master,欢迎指出问题,一针见血的指出问题往往事半功倍。
如果你觉得自己是个大菜鸟,欢迎学习交流。
这个系列主要学习web服务器自定义控件。
而web 服务器控件又分为几种:
HTML服务器控件、<input type=’text’ id=’id1’ runat=’server’>
ASP.NET标准服务器控件 <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
自定义服务器控件:这就是我想学习,想写的重点了。
我觉得吧,学习任何东西,都应该先从微软官方去学习,大概了解了知识后再去网上看其他的博客文章什么的,因为每个人的理解不一样,或者人家理解了,但是写出来的没有完全表达作者真正想表达的意思,要是被误导了不是表示很亏,所以吧,从微软学习后,再看其他文章,你会了解得更准确更多。
当然先从基础的学上,看看微软官方是怎么说的吧。
http://msdn.microsoft.com/zh-cn/library/yhzc935f(v=vs.100).aspx
看完之后,相信你应该会根据这个步骤创建简单的自定义控件了,至少改变一个Label的输出内容是没有问题了,如果我们想写一个登陆的自定义控件,看完第一篇后,是不是表示无从下手啦?是的,我看完之后,表示很是无奈,没事,一步一步来,后面我们将学到这部分知识。
看完微软官方实例之后啊,我觉得有几个东西非常重要,允许重复啰嗦来强调下:
我们看到代码中有几个特性:
[ Bindable(true), Category("Appearance"), DefaultValue(""), Description("The text to display when the user is not logged in."), Localizable(true) ] public virtual string DefaultUserName { get { string s = (string)ViewState["DefaultUserName"]; return (s == null) ? String.Empty : s; } set { ViewState["DefaultUserName"] = value; } }
BindableAttribute . 此特性指定将属性绑定到数据对可视化设计器是否有意义。 例如,在 Visual Studio 中,如果属性标记为 Bindable(true),则该属性可显示在“数据绑定”对话框中。 如果属性没有使用此特性标记,则属性浏览器会推断其值为 Bindable(false)。
CategoryAttribute . 此特性指定如何在可视化设计器的属性浏览器中对属性进行分类。 例如,当页开发人员使用属性浏览器的分类视图时,Category("Appearance") 将告知属性浏览器在“外观”类别中显示属性。 可以指定一个对应于属性浏览器中的现有类别的字符串参数,也可以创建自己的类别。
DescriptionAttribute . 此特性指定属性的简短描述。 在 Visual Studio 中,属性浏览器将在“属性”窗口底部显示选定的属性的描述。<这个我在控件属性中没有看到,不晓得是什么地方错了>。
DefaultValueAttribute . 此特性指定属性的默认值。 此值应与从属性访问器 (getter) 返回的默认值相同。 在 Visual Studio 中,DefaultValueAttribute 特性允许页开发人员通过在“属性”窗口中显示快捷菜单,然后单击“重置”按钮将属性值重置为其默认值。
LocalizableAttribute . 此特性指定本地化属性对可视化设计器是否有意义。 当某属性标记为 Localizable(true) 时,可视化设计器会在将属性序列化为资源时包含该属性值。 对控件轮询可本地化的属性时,设计器会将此属性值保存到非特定于区域性的资源文件或另一个本地化源中。
ViewState:
用于两个属性的 Get 和 Set 方法都利用 ViewState 对象。ViewState 对象是一个内置到 WebControl 类中的帮助器对象。从开发角度讲,ViewState 可被视为一个集合类,用于存储在回发过程中我们想要保留的任意属性。实际上,ViewState 封装了确定如何执行持久性(使用 Cookie、会话等等)所需的所有代码和逻辑。
protected override void RenderContents(HtmlTextWriter writer),
这里就是设计到控件的生命周期了。控件生命周期的Render阶段, 主要将控件标记和字符文本输出到 服务器控件输出流 中. 可以直接写Html标记, 也可以调用每个控件都有的RenderControl方法到输出流. 在WebControl基类中, 以Render开头的呈现方法有如下几个:
RenderControl(HtmlTextWriter writer) Render(HtmlTextWriter writer) RenderBeginTag(HtmlTextWriter writer) RenderContents(HtmlTextWriter output) RenderEndTag(HtmlTextWriter writer)
以上几Render方法中, 并不是毫无联系的, 它们的执行顺序是从上往下, 且有嵌套的调用关系. 其中在RenderControl方法内部会调用Render方法, 在Render方法内部会依次调用RenderBeginTag, RenderContents和RenderEndTag.
其中RenderControl和Render是Control基类中的方法, 因为WebControl本身也是继承Control的. 一般在开发基本控件时, 我们只需求重写RenderContents方法即可, 在此方法中可以把控件Html文本标记和其它内容写到输出流中.
另外, 还有两个可以重载的方法 RenderBeginTag和RenderEndTag, 这两个方法执行时刻点是分别在Render控件内容之前和之后. 可以重写这两个方法自已定义控件的起始和结束标记. 默认情况下控件是以<Span></Span>作为控件起始和结束标记的, 下面是没有重写标记的一个例子的默认显示
这里先看到这个理论知识,后面我们来实践下。
通过这个章节的学习,知道了如何创建与部署到web的整个流程,那么剩下的,就是怎么样做更好更强大的自定义控件了。
我把网页中的Label,通过反射找到源代码,供我们参考了,我们自己编写控件,其实是差不多的
// Generated by .NET Reflector from C:\windows\Microsoft.Net\assembly\GAC_64\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll namespace System.Web.UI.WebControls { using System; using System.ComponentModel; using System.Runtime; using System.Web; using System.Web.UI; using System.Web.Util; [Designer("System.Web.UI.Design.WebControls.LabelDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), ToolboxData("<{0}:Label runat=\"server\" Text=\"Label\"></{0}:Label>"), DataBindingHandler("System.Web.UI.Design.TextDataBindingHandler, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), ParseChildren(false), ControlValueProperty("Text"), ControlBuilder(typeof(LabelControlBuilder)), DefaultProperty("Text")] public class Label : WebControl, ITextControl { private bool _textSetByAddParsedSubObject; [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] public Label() { } [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] internal Label(HtmlTextWriterTag tag) : base(tag) { } protected override void AddAttributesToRender(HtmlTextWriter writer) { string associatedControlID = this.AssociatedControlID; if (associatedControlID.Length != 0) { if (this.AssociatedControlInControlTree) { Control control = this.FindControl(associatedControlID); if (control == null) { if (!base.DesignMode) { throw new HttpException(SR.GetString("LabelForNotFound", new object[] { associatedControlID, this.ID })); } } else { writer.AddAttribute(HtmlTextWriterAttribute.For, control.ClientID); } } else { writer.AddAttribute(HtmlTextWriterAttribute.For, associatedControlID); } } base.AddAttributesToRender(writer); } protected override void AddParsedSubObject(object obj) { if (this.HasControls()) { base.AddParsedSubObject(obj); } else if (obj is LiteralControl) { if (this._textSetByAddParsedSubObject) { this.Text = this.Text + ((LiteralControl) obj).Text; } else { this.Text = ((LiteralControl) obj).Text; } this._textSetByAddParsedSubObject = true; } else { string text = this.Text; if (text.Length != 0) { this.Text = string.Empty; base.AddParsedSubObject(new LiteralControl(text)); } base.AddParsedSubObject(obj); } } protected override void LoadViewState(object savedState) { if (savedState != null) { base.LoadViewState(savedState); if ((((string) this.ViewState["Text"]) != null) && this.HasControls()) { this.Controls.Clear(); } } } protected internal override void RenderContents(HtmlTextWriter writer) { if (base.HasRenderingData()) { base.RenderContents(writer); } else { writer.Write(this.Text); } } [Themeable(false), WebSysDescription("Label_AssociatedControlID"), DefaultValue(""), IDReferenceProperty, TypeConverter(typeof(AssociatedControlConverter)), WebCategory("Accessibility")] public virtual string AssociatedControlID { get { string str = (string) this.ViewState["AssociatedControlID"]; if (str != null) { return str; } return string.Empty; } set { this.ViewState["AssociatedControlID"] = value; } } internal bool AssociatedControlInControlTree { get { object obj2 = this.ViewState["AssociatedControlNotInControlTree"]; if (obj2 != null) { return (bool) obj2; } return true; } set { this.ViewState["AssociatedControlNotInControlTree"] = value; } } internal override bool RequiresLegacyRendering { get { return true; } } public override bool SupportsDisabledAttribute { get { return (this.RenderingCompatibility < VersionUtil.Framework40); } } protected override HtmlTextWriterTag TagKey { get { if (this.AssociatedControlID.Length != 0) { return HtmlTextWriterTag.Label; } return base.TagKey; } } [Localizable(true), PersistenceMode(PersistenceMode.InnerDefaultProperty), Bindable(true), WebCategory("Appearance"), DefaultValue(""), WebSysDescription("Label_Text")] public virtual string Text { get { object obj2 = this.ViewState["Text"]; if (obj2 != null) { return (string) obj2; } return string.Empty; } set { if (this.HasControls()) { this.Controls.Clear(); } this.ViewState["Text"] = value; } } } }
这里有个网页写得不错,看完后,希望你能收获更多.
http://blog.csdn.net/huang7914/article/details/2329261