最近看到公司某个网站中用到了自定义控件,咋一眼看去,不明白什么玩意,

网上一搜,好像确实不是几句话就能写出强大的自定义控件。好吧,作为一个码农,我决定从基本学起,写一个关于自定义控件学习过程系列。

当然了,我只是学习这个系列,不是作为一个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自定义控件系列(一)的更多相关文章

  1. ASP.NET自定义控件组件开发 第五章 模板控件开发

    原文:ASP.NET自定义控件组件开发 第五章 模板控件开发 第五章 模板控件开发 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.NET自定义控件组件开发 第一章 第二篇 接 ...

  2. ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl

    原文:ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 第四章 组合控件开发CompositeControl 大家好,今天我们来实现一个自定义的控件,之前我们已经 ...

  3. ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡

    原文:ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡 CompositeControl  后篇 --事件冒泡 系列文章链接: ASP.NET ...

  4. ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇

    原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇 第三章 为控件添加事件 好了,我们之前以前开发一个控件.而且也添加了属性,开发也很规范,但是那个控件还差最后一点:添加事件. 系列 ...

  5. ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇

    原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇 第三章 为控件添加事件 后篇 前一篇文章只是简单的说了下事件,但是大家应该方法,在ASP.NET自定义控件中只是简单那么定义事件是 ...

  6. ASP.NET自定义控件组件开发 第一章 第三篇

    原文:ASP.NET自定义控件组件开发 第一章 第三篇 第三篇:第一章的完结篇 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.NET自定义控件组件开发 第一章 第二篇 接着待 ...

  7. ASP.NET自定义控件组件开发 第二章 继承WebControl的自定义控件

    原文:ASP.NET自定义控件组件开发 第二章 继承WebControl的自定义控件 第二章 继承于WebControl的自定义控件 到现在为止,我已经写了三篇关于自定义控件开发的文章,很感谢大家的支 ...

  8. ASP.NET自定义控件组件开发 第一章 第二篇 接着待续

    原文:ASP.NET自定义控件组件开发 第一章 第二篇 接着待续 ASP.NET自定义控件组件开发 第一章 第二篇 接着待续 很感谢大家给我的第一篇ASP.NET控件开发的支持!在写这些之前,我也看了 ...

  9. ASP.NET自定义控件组件开发 第一章 待续

    原文:ASP.NET自定义控件组件开发 第一章 待续 第一章:从一个简单的控件谈起 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.NET自定义控件组件开发 第一章 第二篇 接 ...

随机推荐

  1. Leetcode 89

    回溯写到自闭:不想就删了: class Solution { public: vector<int> grayCode(int n) { vector<vector<int&g ...

  2. Python的数据类型1数值和字符串

    Python的交互器 在讲这个之前,我要先讲一下python的交互器,之后讲解代码(除了做简单项目)都在交互器上进行,这样可能比较直接一些,有利于刚接触python的人理解代码 python在命令行自 ...

  3. spring cloud 学习(二)关于 Eureka 的学习笔记

    关于 Eureka 的学习笔记 个人博客地址 : https://zggdczfr.cn/ ,欢迎光临~ 前言 Eureka是Netflix开发的服务发现组件,本身是一个基于REST的服务.Sprin ...

  4. tensorflow安装相关问题

    安装步骤 要求:Python必须是64位根据TensorFlow的计算方式,TensorFlow的安装分为CPU版本和GPU版本对于Python3.5或者Python3.6,可以使用pip insta ...

  5. python中read()、readline()、readlnes()

    在python中 1.file.read()直接按原样读取文件,它通常用于将文件内容放到一个字符串变量中,如果文件大于可用内存,则不可能实现这种处理,因为原来文件里面是str_class,所以 fil ...

  6. C++ error C2440: “类型转换” : 无法从“std::vector::iterator”转换为“

    原文地址:http://blog.csdn.net/onlyou930/article/details/5602654 圆环套圆环之迭代器 话说这一日是风平浪静,万里乌云,俺的心情好的没得说,收到命令 ...

  7. Final阶段第1周/共1周 Scrum立会报告+燃尽图 02

    作业要求[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2481] 版本控制:https://git.coding.net/liuyy08 ...

  8. SpringAop与AspectJ

    AspectJ AspectJ是一个面向切面的框架,它扩展了Java语言.AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件. spring ao ...

  9. Java乱码解决之道

    1.常见字符编码 ASCII编码: ASCII,American Standard Code for Information Interchange,是基于拉丁字母的一套电脑编码系统,主要用于显示现代 ...

  10. 51Nod:完美字符串

    约翰认为字符串的完美度等于它里面所有字母的完美度之和.每个字母的完美度可以由你来分配,不同字母的完美度不同,分别对应一个1-26之间的整数. 约翰不在乎字母大小写.(也就是说字母F和f)的完美度相同. ...