Clingingboy

<developer name=’'clingingboy">
<i:Interaction.Behaviors>
<clingingboy:madeControlBehavior />
</i:Interaction.Behaviors>
</developer>

博客园 首页 新随笔 联系 订阅 管理
  211 Posts :: 1 Stories :: 1439 Comments :: 484 Trackbacks
上一篇:http://www.cnblogs.com/Clingingboy/archive/2006/07/30/463471.html
或许大家还对为何要重写Render方法存有疑惑,希望大家看看我举的例子,能够明白Render方法和其他两个方法的作用,然后真正明白为何一般情况下只须重写Render方法

我们知道我们每次编写控件时,都需要重写Render方法,我们发现在Control类中很多方法可以重写,但我们没有去重写他们,我们需要遵循一个原则,在需要重载的时候再去重写他们

我们还是先来看看与Render方法相关的两个方法
//RenderControl方法的基本实现
 public void RenderControl(HtmlTextWriter writer)
 
{
 
if(Visible)
 
{
 Render(writer);
 }

 }

 
//Render方法基本实现
 protected virtual void Render(HtmlTextWriter writer)
 
{
 RenderChildren(writer);
 }

 
//RenderChildren方式基本实现
 protected virtual void RenderChildren(HtmlTextWriter writer)
 
{
 
foreach (Control c in Controls)
 
{
 c.RenderControl(writer);
 }

 }

相信看过"ASP.NET服务器控件开发技术与实例"这本书的人,肯定看过上面的一段代码.

假设你不理解上面的流程(我也不一定理解,希望我的思路对你有帮助),我认为有一种很好的方式来理解上面的流程,跟大家分享一下.

现在抛开上面的代码,我们来建一个简单的页面,随意的拖几个控件到界面上,注意最后一个三panel控件,如下图


图一

我们知道,每个控件都有Visible和EnableViewState属性,Visible用来设置控件是否被呈现.


图二

现在我们把button控件的Visible属性设置为flase,我们看到了我们预期的效果,接着请启用页面跟踪,这个很重要


图三

在服务器上运行这个页面,大家可以在控件树上看到下面画面


图四

(1)System.Web.UI.LiteralControl

大家可以看到,在我们定义的每个控件之间都有System.Web.UI.LiteralControl.
这里需要说明的是,要理解任何不需要在服务器上处理的任何其他字符串.

如何理解呢?大家打开这个运行页面的源代码页面,如下代码,大家看到没有,除了服务器控件外,我们有其他元素(不需要在服务器上处理的任何其他字符串),包括空格.

示例一
<!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><title>
  鏃犳爣棰橀〉
</title></head>
<body>
 
<form name="form1" method="post" action="Default1.aspx" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwULLTExNTUxMDYxODdkZHVaWm47e5anDettRKviGvS0nDWQ" />
</div>

 
<div>
 
<span id="Label1">Label</span><br />
 
<br />
 
<input name="TextBox1" type="text" id="TextBox1" /><br />
 
<br />
 
<br />
 
<br />
 
<div id="Panel1" style="height:50px;width:125px;">
  
 
</div>
 
&nbsp;</div>
 
<div>

  
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWAgK/5/fTBwLs0bLrBrVw7YrSp5G/l4sJGPkKN/asFj2W" />
</div></form>
</body>
</html>

为了让大家更加明白System.Web.UI.LiteralControl的意思的,让我们来修改HTML页面,说明:以上代码为运行后的HTML源代码.而不是我们所说的源代码,大家应该明白我所指的源代码的意思.

我们来修改代码,注意:我把<form..以下的标签无空格的写在了一起.看下面修改后的代码

示例二
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" Trace="true" %>

<!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>
</head>
<body>
 
<form id="form1" runat="server"><asp:Label ID="Label1" runat="server" Text="Label"></asp:Label><asp:TextBox ID="TextBox1" runat="server"></asp:TextBox><asp:Button ID="Button1" runat="server" Text="Button" Visible="False" /><asp:Panel ID="Panel1" runat="server" Height="50px" Width="125px"></asp:Panel></form>
</body>
</html>

运行效果


图五

现在发现控件之间已经没有System.Web.UI.LiteralControl了,因为我去掉了空格.这个也说明了一点,如果代码很乱的话会影响速度.现在大家应该明白System.Web.UI.LiteralControl的意思了吧.

(2)大家继续看图四的Button1,大家会发现它呈现的大小字节数为0,因为我们设置了Button1的Visible值为False,所以未呈现此控件.

下面我们来理解这一点,大家重新看到RenderControl方法,如果Visible值为True则呈现此控件.
if(Visible)
 Render(writer);

为了理解这个方法,我们来重写此方法,我们以第一次讲的CreditCardForm3控件为例

我们重写RenderControl方法,把Render方法的代码全部拷贝到RenderControl方法中,然后去掉Render方法

然后在asp.net页面使用此控件,定义其Visible值为False

图六

运行这个例子以后,你会发现控件还是呈现了,就是因为你重写了RenderControl方法,使控件的Visible值无效了

所以我们就要加上一个判断
if(Visible) {}


否则的话,此方法呈现的内容没有Visible值.为了更加深刻理解这一点,我们重写基类的RenderControl方法的方法.

base.RenderControl(writer);

你会发现在页面呈现时的控件有两个,一个在RenderControl方法方法输出,一个在Render方法输出,因为
base.RenderControl方法调用了Render方法,当设置控件Visible属性为False时,Render方法输出的内容被隐藏(未被呈现,而RenderControl方法输出的内容仍然存在.现在大家应该了解RenderControl方法的作用了吧.

如果服务器控件的 Visible 属性设置为 true,则向页呈现服务器控件的内容,所以一般情况下我们不重写此方法.因为一般控件都需要Visible 属性,除非特殊情况.
图七

(3)RenderChildren方法

再重新看到图四,大家可以看到,我们拖放的控件是在属于form1的子控件,panel控件是一个容器控件,因为下面没拖放控件,任何其他显示的字符串表现为System.Web.UI.LiteralControl,大家可以拖几个控件到panel里再重新运行看看,会发现拖进去的控件变为panel的子控件.最明显的的测试方法是Wizard控件,拖放一个Wizard控件然后再测试你就会明白了.

RenderChildren方法则判断当前控件是否有子控件,如果有,则根据RenderControl方法判断控件的Visible值来呈现控件.所以大家在重写Render方法时,不重写基类Render方法时,将无法实现RenderChildren方法.带来的后果将是无法呈现子控件.

下面我们来测试一下.我们还是以CreditCardForm3控件为例子(请先把RenderControl方法的内容全注释掉),当未重实现RenderChildren方法时则无法呈现子控件内容,请启动跟踪

将发现其子控件呈现字节为0

图八

由于CreditCardForm3继承了CreditCardForm2,所以重写基类Render方法将会重复输出,我们可以直接在Render方法中重写RenderChildren方法.再来测试.将会发现有些变化

发现其子控件呈现字节并非为0,而是10

图九

说明其子控件还是存在东西的,只不过没有用而已,所以大家可以根据实际需求来确实是否要重写RenderChildren方法,一般的话都会重写Render方法,这样保险一点

好了,现在再来回顾下刚开始给出的代码,通过上面的试验,你是否明白了?

呈现控件的步骤(注意:下面三个方法都可以呈现,不过我们已经说过了,像在RenderControl方法用HtmlTextWriter预先输出的话,就丧失Visible的功能(说不定你就不需要这个功能,那时你就可以重写这个方法了)

(1)RenderControl方法

先判断其Visible然后调用Render方法

(2) Render方法

使用HtmlTextWriter将标记字符和文本输出然后调用RenderChildren方法

(3)RenderChildren方法

判断当前控件是否有子控件,然后再调用RenderControl方法根据子控件的Visible值输出子控件.

我们了解上面三个方法后,就会知道,一般情况下,我们无须重写RenderControl方法和RenderChildren方法.所以最合适的就是重写Render方法了.说了一大堆.目的就是为了说明为什么要重写Render方法.

上次,忘了把代码传上了,不小心只上传了dll文件,不好意思.这次就写这么多.希望大家能够真正明白.大家可以适当的修改代码,这样你会发现更多.

参考文章:ASP.NET2.0服务器控件之Render方法

点击下载示例代码

如果有什么错误请大家指出,希望多跟大家交流^_^
posted on 2006-08-01 21:36 Clingingboy 阅读(25065) 评论(69)  编辑 收藏 网摘 所属分类: B Asp.net组件开发

Feedback

#1楼 2006-08-02 08:47 Hover      
好文章!!
  回复  引用  查看    

#2楼 2006-08-02 09:36 7ero      
你的文章很棒
下次能不能给出诊么写带子控件或模板控件的方法?如DataList中是怎么用到ItemTemplate的

  回复  引用  查看    

#3楼[楼主] 2006-08-02 09:57 Clingingboy      
谢谢夸奖,有你们的支持我就更有信心写下去了,只有我真正理解掌握了,我才能用通俗的语句来表达,我发现我在写的过程,明白了很多
  回复  引用  查看    

#4楼 2006-08-02 16:05 Minwell      
一直想学这方面的东西,一直没时间, 不知道各位是不是也成天忙得时间由不得自己作主????
  回复  引用  查看    

#5楼 2006-08-21 18:05 blueshop[未注册用户]
太好了,正在学习控件,有好多东西还不懂,看了你的文章后,终于有了一些头绪了。目前我写的都是WEB用户控件,想改成用户控件,希望有更好的文章学习。谢谢!
  回复  引用    

#6楼 2006-09-15 12:49 erdong
我建议重写RenderContents方法,首先我们看看.net自己在Render方法中作了什么
protected override void Render(HtmlTextWriter writer)
{
this.RenderBeginTag(writer);
this.RenderContents(writer);
this.RenderEndTag(writer);
}
然后再看看
protected virtual void RenderContents(HtmlTextWriter writer)
{
base.Render(writer);
}
。如果你直接重写了Render方法,就需要自己调用RenderBeginTag/RenderEndTag等方法。




  回复  引用    

#7楼[楼主] 2006-09-15 13:42 Clingingboy      
@erdong
朋友请看下文^_^

http://www.cnblogs.com/Clingingboy/archive/2006/08/05/468694.html">http://www.cnblogs.com/Clingingboy/archive/2006/08/05/468694.html

  回复  引用  查看    

#8楼 2006-11-20 13:07 gggg[未注册用户]
都是virtual 方法
  回复  引用    

请问控件可以使用API函数吗?
好像使用了API函数后,控件调试后通过,但是放在网页里面不能用

  回复  引用    

谢谢分享 谢谢
  回复  引用    

接着请启用页面跟踪,这个很重要
????请问在那里???

  回复  引用    

#12楼[楼主] 2007-01-11 18:42 Clingingboy      
下面不是有张图给你吗
Trace=true

  回复  引用  查看    

#13楼 2007-02-12 11:28 Klesh Wong      
同意erdong同志的说法,msdn上也是提倡改写
this.RenderBeginTag(writer);
this.RenderContents(writer);
this.RenderEndTag(writer);
这三个方面,不建议直接改写Render方法.

  回复  引用  查看    

#14楼[楼主] 2007-02-12 11:36 Clingingboy      
@Klesh Wong
那是继承webcontrol的做法.
其实我感觉是一样的,只是在webcontrol里RenderContents里重写了头标签.当然继承webcontrol后,RenderContents方法代替了Render方法

  回复  引用  查看    

#15楼 2007-03-11 09:03 ASP.NET[未注册用户]
不错,正学习中...
  回复  引用    

真是好文章,對我控件開發大有幫助。
  回复  引用    

#17楼 2007-03-21 17:22 nnh[未注册用户]
楼主,打码下了打不开呀,麻烦更正一下呀.谢谢.
  回复  引用    

#18楼[楼主] 2007-03-21 17:44 Clingingboy      
@nnh
已经更正了,跟第一篇代码一样的

  回复  引用  查看    

楼主,每组图片的前2个都打不开,就只能看见最后一个,可不可以修改一下吖,这样看,这篇文章完全看不懂吖
  回复  引用    

#20楼[楼主] 2007-04-03 13:21 Clingingboy      
@silentwins
不好意思,没注意到,我改

  回复  引用  查看    

改得好快,谢谢了!!!
  回复  引用    

原来显示不出来的图都是多余的?害我一直还想象那些是什么图,晕死了~_~!
  回复  引用    

#23楼 2007-04-17 21:21 steven love sunny      
好文章,写得通俗易懂,循序渐进地给初学者掌握如何自定义一个控件,希望你能再接再厉!
  回复  引用  查看    

#24楼 2007-05-14 14:06 耐心[未注册用户]
佩服你的耐心
  回复  引用    

#25楼 2007-05-14 14:06 耐心[未注册用户]
@耐心

  回复  引用    

#26楼 2007-05-17 16:10 zengkj[未注册用户]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace innerEditorCtrl
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:innerEditor runat=server></{0}:innerEditor>")]
public class innerEditor : WebControl
{
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string Text
{
get
{
String s = (String)ViewState["Text"];
return ((s == null) ? String.Empty : s);
}

set
{
ViewState["Text"] = value;
}
}

protected override void RenderContents(HtmlTextWriter output)
{
output.Write(Text);
}
}
}

  回复  引用    

#27楼 2007-06-11 10:25 pgg[未注册用户]
不错,很通俗,支持一下.
  回复  引用    

#28楼 2007-06-16 21:38 kan[未注册用户]
好东西,下了慢慢看
  回复  引用    

#29楼 2007-08-09 16:46 牛鸿宇
按你说的做了 还下了你的源码。重写RenderControl(writer)方法把Visible设为False是能显现控件, 可把Visible设为Ture还是一个阿 怎么也出不来两个控件……
  回复  引用    

#30楼[楼主] 2007-08-09 22:27 Clingingboy      
前面1,2,3的源码在一起了,所以可能会错,如果你明白了就可以过了
  回复  引用  查看    

#31楼 2007-08-10 09:25 牛鸿宇
谢谢 呵呵, 继续往下看,支持楼主 !
  回复  引用    

#32楼 2007-08-11 15:37 hanjoe[未注册用户]
超级感谢楼主!
  回复  引用    

#33楼 2007-11-03 13:10 KaKaXu      
顶,楼主理解得好透彻。。
  回复  引用  查看    

#34楼 2007-12-19 20:16 阿鹏      
又学了一篇,感谢下楼主.以后每学一篇,感谢一下,哈
  回复  引用  查看    

#35楼 2008-01-02 10:12 JINHUTT[未注册用户]
非常GOOD!呵呵!
  回复  引用    

#36楼 2008-01-07 14:45 igelf[未注册用户]
@牛鸿宇

因为write为空,所以没有.
if (Visible)
{
Render(writer);
}
writer.Write("<table ..");
base.Render(writer);
这样就有了.

  回复  引用    

public override string PaymentMethodText
{
get { return ViewState["PaymentMethodText"] != null ? (string)ViewState["PaymentMethodText"] : "信用卡类型"; }
set { ViewState["PaymentMethodText"] = value; }
}
我这得不到ViewState啊,已经设置了Page和Control的 EnableViewState="true"。请有空时帮忙,谢谢!

  回复  引用    

#38楼[楼主] 2008-01-21 16:02 Clingingboy      
@CodeLover
应该不会吧

  回复  引用  查看    

#39楼 2008-03-17 11:34 天生俪姿      
问下楼主 你的图四的载图 是怎么弄出来的哟?
多谢。

  回复  引用  查看    

#40楼 2008-03-18 10:25 SZW      
好文章,支持楼主!
  回复  引用  查看    

多谢博主共享!认真看了几遍!受益匪浅!加油!
  回复  引用    

我在控件之间加上<br />就产生了LiteralControl。
  回复  引用    

@SZW
我顶!

  回复  引用    

#44楼 2008-06-12 17:09 和尚释然      
你的文章我初一看很喜欢,再仔细一看太喜欢了!
博主向你学习!

  回复  引用  查看    

非常深刻!很有启发!
谢谢!

  回复  引用    

#46楼 2008-07-10 16:26 火无极      
RenderControl,Render,RenderChildren这三个方法讲得真是清晰啊,控件开发第二课学习了,谢谢
  回复  引用  查看    

#47楼 2008-08-03 20:25 lention[未注册用户]
学习中,每天一篇你的文章。呵呵

  回复  引用    

#48楼 2008-08-06 16:12 丛林之王      
看的不怎么懂哦
  回复  引用  查看    

#49楼 2008-08-06 16:17 丛林之王      
我用VS2005建了个项目 ,我把你的代码复杂进去 CreditCardForm2.cs,CreditCardForm3.cs,生成后 引用DLL 怎么都是CreditCardForm2控件啊!应该是CreditCardForm3这个控件啊!难道要设置CreditCardForm3.cs为启动项吗?
  回复  引用  查看    

#50楼[楼主] 2008-08-06 18:44 Clingingboy      
@丛林之王
两者可能是继承关系,介绍的是不同做法,可能最终显示的效果是相同的。启动项应该为web项目

  回复  引用  查看    

#51楼 2008-08-11 15:23 丛林之王      
已经可以了,谢谢LZ
  回复  引用  查看    

#52楼 2008-09-17 18:03 pingle[未注册用户]
讲的真透彻学习了!

  回复  引用    

我重写RenderControl方法时,提示:无法重写继承成员"System.Web.UI.Control.RenderControl(System.Web.UI.HtmlTextWriter)"
因为它未标识为virtual、abstract或override
怎么回事?

  回复  引用    

#54楼 2008-12-17 12:36 游客[未注册用户]
狂顶!
  回复  引用    

#55楼 2008-12-24 14:39 yangxh      
讲的真透彻,继续学习!!
  回复  引用  查看    

#56楼 2009-03-03 10:25 nianshi[未注册用户]
好文章…………
  回复  引用    

--引用--------------------------------------------------
风已吹过: 我重写RenderControl方法时,提示:无法重写继承成员&quot;System.Web.UI.Control.RenderControl(System.Web.UI.HtmlTextWriter)&quot;
因为它未标识为virtual、abstract或override
怎么回事?
--------------------------------------------------------

overvide RenderCOntrol(HtmlTextWriter writer){
//..............
//.........
}

  回复  引用    




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 465397




相关文章:

相关链接: