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
Asp.net自定义控件系列(一)的更多相关文章
- ASP.NET自定义控件组件开发 第五章 模板控件开发
原文:ASP.NET自定义控件组件开发 第五章 模板控件开发 第五章 模板控件开发 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.NET自定义控件组件开发 第一章 第二篇 接 ...
- ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl
原文:ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 第四章 组合控件开发CompositeControl 大家好,今天我们来实现一个自定义的控件,之前我们已经 ...
- ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡
原文:ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡 CompositeControl 后篇 --事件冒泡 系列文章链接: ASP.NET ...
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇
原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇 第三章 为控件添加事件 好了,我们之前以前开发一个控件.而且也添加了属性,开发也很规范,但是那个控件还差最后一点:添加事件. 系列 ...
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇
原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇 第三章 为控件添加事件 后篇 前一篇文章只是简单的说了下事件,但是大家应该方法,在ASP.NET自定义控件中只是简单那么定义事件是 ...
- ASP.NET自定义控件组件开发 第一章 第三篇
原文:ASP.NET自定义控件组件开发 第一章 第三篇 第三篇:第一章的完结篇 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.NET自定义控件组件开发 第一章 第二篇 接着待 ...
- ASP.NET自定义控件组件开发 第二章 继承WebControl的自定义控件
原文:ASP.NET自定义控件组件开发 第二章 继承WebControl的自定义控件 第二章 继承于WebControl的自定义控件 到现在为止,我已经写了三篇关于自定义控件开发的文章,很感谢大家的支 ...
- ASP.NET自定义控件组件开发 第一章 第二篇 接着待续
原文:ASP.NET自定义控件组件开发 第一章 第二篇 接着待续 ASP.NET自定义控件组件开发 第一章 第二篇 接着待续 很感谢大家给我的第一篇ASP.NET控件开发的支持!在写这些之前,我也看了 ...
- ASP.NET自定义控件组件开发 第一章 待续
原文:ASP.NET自定义控件组件开发 第一章 待续 第一章:从一个简单的控件谈起 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.NET自定义控件组件开发 第一章 第二篇 接 ...
随机推荐
- 『PyTorch』第五弹_深入理解Tensor对象_中上:索引
一.普通索引 示例 a = t.Tensor(4,5) print(a) print(a[0:1,:2]) print(a[0,:2]) # 注意和前一种索引出来的值相同,shape不同 print( ...
- 牛客网暑期ACM多校训练营(第三场)DEncrypted String Matching fft
题意:给你一个解密后的字符串,给你加密方式,加密过程可能出错,字符可能加减1,然后给你一个字符串,要求匹配个数(其实我也不太懂具体怎么加密解密,反正你把给你的前两个字符串用第三个加密一下,然后搞可以有 ...
- 转化为json方式函数
1,我的数据格式是: {"message":"","code":0,"data":[{"Order" ...
- HDU1789时间贪心
Doing Homework again Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...
- UVA-1626 Brackets sequence (简单区间DP)
题目大意:给一个有小括号和中括号组成的序列,满足题中的三个条件时,是合法的.不满足时是不合法的,问将一个不合法的序列最少添加几个括号可以使之变成合法的.输出最短合法序列. 题目分析:这是<入门经 ...
- linux单用户模式
linux单用户模式 2014年11月11日 17:18 在grub上相应要启动的内核上按“e”. 进入下一界面,继续按“e”. 在进入文本界面后,输入“single”回车. 进入grub界面后,按“ ...
- NuGet 控制台代码
安装 Bootstrap 包:Install-package -version 3.0.0 bootstrap -projectname SportsStore.WebUI 这三句常常连用,在不同项目 ...
- elasticsearch 路由文档到分片
路由文档到分片 当你索引一个文档,它被存储在单独一个主分片上.Elasticsearch是如何知道文档属于哪个分片的呢?当你创建一个新文档,它是如何知道是应该存储在分片1还是分片2上的呢? 进程不能是 ...
- win10 移动热点自动关闭
解决win10移动热点自动关闭
- POJ 2109 巧妙解法
Int最大是10^9.所以一般思路是二分+高精度.但是double 范围是10^(-307)-10^308所以可以用double型.k^n=p.所以有k=p^(1/n). 见代码: #include& ...