- 浏览: 103475 次
- 性别:
- 来自: 南京
文章分类
最新评论
概述
在此之前我已经在4Guys网站上写过两篇和此文章关联的文章,分别为:ASP.NET中的动态控件(Dynamic Controls in ASP.NET) 和怎样操作动态生成的控件(Working with Dynamically Created Controls) 。微软的ASP.NET平台可以让我们通过编程的方式方便的动态在页面上添加控件,拥有了这个有力武器,我们可以为我们的用户提供真正意义上的个性化体验。比如你可以根据登录用户的喜好动态设置导航系统,或者你可以根据用户的不同年龄、地址、性别或者其他因素来显示不同的调查问卷。
但是使用动态生成控件的一个挑战是你必须在每次页面回传时都需要通过编码的方式来重新添加这些控件,而不能仅仅在第一次载入界面的时候添加一次。如果你不这样做,那么你会发现在页面回传以后(PostBack)所有动态添加的控件都消失了。更加复杂的情况是如何在页面回传过程(PostBack)中保持动态添加控件的值。比如你在页面上动态的添加了几个文本框(TextBox),然后用户可以在这些文本框中填写一些信息,并且点击一下页面的“保存”按钮对页面信息进行保存操作。如果你不能在页面生命周期的合适位置添加动态生成的控件,用户填写的信息将在页面回传后丢失。
In this article we will examine how to add dynamic Web controls to a page in such a manner that you will not need to worry about losing form field values on postback. Specifically, we'll look at how to create a page whose form fields are dependent upon the user visiting the page, and how this user can enter their data into these form fields and have it saved on form submission. Since this article builds upon concepts discussed earlier, please make sure you have read both Dynamic Controls in ASP.NET and Working with Dynamically Created Controls before tackling this article.
Understanding the Page Lifecycle
As page developers, we often think about ASP.NET Web pages consisting of two distinct portions: an HTML portion and a code-behind class. However, behind the scenes, when an ASP.NET Web page is requested for the first time (or for the first time after the page has changed) the HTML portion is autogenerated into a class from which the code-behind class is derived from. In essence, an ASP.NET Web page is represented, then, as a single class. Whenever an ASP.NET page is requested from the Web server, the corresponding page's class is instantiated and its ProcessRequest()
method is invoked. This method kicks off the page lifecycle. The page lifecycle is a sequence of stages that the ASP.NET page's corresponding class progresses through. The end goal of the lifecycle is to generate the page's appropriate markup, which is then sent back to the requesting browser.
The page lifecycle is composed of a number of steps, the following ones being the ones of interest for this article:
- Instantiation,
- Initialization,
- Load View State,
- Load,
- Save View State
The first stage if the page lifecycle is called Instantiation, and in this stage the page's control hierarchy is created. The control hierarchy is the hierarchy of server controls that exist in the page. Typically this includes an HtmlForm
(the <form runat="server">
), numerous LiteralControls
(static HTML content in the page's HTML portion is represented as LiteralControls
in the hierarchy), and the Web controls you added to the page's HTML portion. The control hierarchy is created by the autogenerated class. Since every time an ASP.NET page is requested, be it the first time or on a subsequent postback, the page class is reinstantiated and reiterates its lifecycle, each request causes the control hierarchy to be rebuilt from scratch in the Instantiation stage.
As mentioned earlier, the ASP.NET page's autogenerated class's responsibility is to create the control hierarchy from the HTML portion. To understand this process, let's look at a concrete example. This example - the complete text and images below - is taken from another article of mine, Understanding ASP.NET View State, published on MSDN Online in May 2004.
Imagine you have an ASP.NET Web page with the following HTML portion:
<html><body> <h1>Welcome to my Homepage!</h1> <form runat="server"> What is your name? <asp:TextBox runat="server" ID="txtName"></asp:TextBox> <br />What is your gender? <asp:DropDownList runat="server" ID="ddlGender"> <asp:ListItem Select="True" Value="M">Male</asp:ListItem> <asp:ListItem Value="F">Female</asp:ListItem> <asp:ListItem Value="U">Undecided</asp:ListItem> </asp:DropDownList> <br /> <asp:Button runat="server" Text="Submit!"></asp:Button> </form></body></html>When this page is first visited, a class will be autogenerated that contains code to programmatically build up the control hierarchy. The control hierarchy for this example can be seen in the figure below.
This control hierarchy is then converted to code that is similar to the following:
Page.Controls.Add( new LiteralControl(@"<html>/r/n<body>/r/n <h1>Welcome to my Homepage!</h1>/r/n"));HtmlForm Form1 = new HtmlForm();Form1.ID = "Form1";Form1.Method = "post";Form1.Controls.Add( new LiteralControl("/r/nWhat is your name?/r/n"));TextBox TextBox1 = new TextBox();TextBox1.ID = "txtName";Form1.Controls.Add(TextBox1);Form1.Controls.Add( new LiteralControl("/r/n<br />What is your gender?/r/n"));DropDownList DropDownList1 = new DropDownList();DropDownList1.ID = "ddlGender";ListItem ListItem1 = new ListItem();ListItem1.Selected = true;ListItem1.Value = "M";ListItem1.Text = "Male";DropDownList1.Items.Add(ListItem1);ListItem ListItem2 = new ListItem();ListItem2.Value = "F";ListItem2.Text = "Female";DropDownList1.Items.Add(ListItem2);ListItem ListItem3 = new ListItem();ListItem3.Value = "U";ListItem3.Text = "Undecided";DropDownList1.Items.Add(ListItem3);Form1.Controls.Add( new LiteralControl("/r/n<br /> /r/n"));Button Button1 = new Button();Button1.Text = "Submit!";Form1.Controls.Add(Button1);Form1.Controls.Add( new LiteralControl("/r/n</body>/r/n</html>"));Controls.Add(Form1);The C# source code above is not the precise code that is autogenerated by the ASP.NET engine. Rather, it's a cleaner and easier to read version of the autogenerated code. To see the full autogenerated code - which won't win any points for readability - navigate to the
WINDOWS/Microsoft.NET/Framework/Version/Temporary ASP.NET Files
folder and open one of the.cs
or.vb
files.One thing to notice is that, when the control hierarchy is constructed, the properties that are explicitly set in the declarative syntax of the Web control are assigned in the code. (For example, the Button Web control has its
Text
property set to "Submit!" in the declarative syntax –Text="Submit!"
– as well as in the autogenerated class —Button1.Text = "Submit!";
.
The page's control hierarchy created in the Instantiation stage reflects the markup in the page's HTML portion. When we add controls dynamically to an ASP.NET Web page, we are essentially building onto this control hierarchy, but at a later stage in the page lifecycle.
After the Instantiation stage, the page lifecycle enters the Initialization stage. In this stage, the page's Init
event is fired, along with the Init
event of the page's server controls.
Following the Initialization stage, the page's view state is restored in the Load View State stage. Each ASP.NET server control is capable of maintaining its state across postbacks through a mechanism known as view state. View state is utilized when a control's state - its properties - are modified programmatically. Recall that in the Instantiation stage, when the control hierarchy is build, the controls' properties are assigned their default values (namely the values specified in their declarative syntax). If any properties are set programmatically, in the code-behind class, then these changes must be remembered across postbacks. Any state change is remembered across postback through view state.
A profound understanding of view state isn't vital for this article. What's vital is to realize that prior to the Load View State the controls' properties are assigned the values specified in the declarative syntax in the HTML portion. After the Load View State, the controls' properties have the actual values (assuming there have been changes to their state on a prior postback). However, if you are interested in learning more about ASP.NET's view state, be sure to read: Understanding ASP.NET View State. |
Following the Load View State stage, the page enters the Load stage, which fires the Load
event for the page and its controls. You are likely familiar with the Load stage, since virtually every ASP.NET Web page out there has some code in its Page_Load
event handler, which is the event handler that runs when the page's Load
event fires. Sometime after the Load stage, the Save View State stage begins, which entails persisting the view state of the controls on the page into a hidden form field named __VIEWSTATE
. (This hidden form field is how this view state is persisted across postbacks.)
These four stages in the page lifecycle are just a subset of the stages the page proceeds through during its lifecycle. For a more in-depth look at the lifecycle you can read Dino Esposito's article: The ASP.NET Page Object Model.
Adding Controls at the Right Time
We already know that when adding controls dynamically through the page's code portion the controls must be added on every postback. But when in the page lifecycle should the controls be added? At first guess, we might decide to put such code in the Page_Load
event handler, causing the controls to be added during the Load stage of the page's lifecycle. This would work fine if we don't need to worry about saving the controls' view state across postbacks, but if we do need to persist the view state of the dynamically added controls the Load stage is not where we should be adding these controls.
If we need our dynamically added controls to maintain their view state it is paramount that these controls be added before the Load View State stage. That is, these controls must exist within the page's control hierarchy before the view state is loaded. There's only one stage before Load View State - Initialization. That means, if we want our dynamic controls to persist view state we must add them to the control hierarchy in the page's Init
event.
If you are using Visual Studio .NET, the code-behind class already contains an event handler for the page's Init
event. This event handler (named Page_Init
in VB.NET code-behind classes and OnInit
in C# code-behind classes) is tucked away in the hidden "Web Form Designer Generated Code" region. What I typically do is create a separate method in the code-behind class and simply call this method from the Init
event handler. Once you have configured everything so that the dynamic controls are added during the Initialization stage, you can then read/write the controls' properties in the Load stage. You'll find that the users' interactions with the dynamic controls remains "remembered" across postbacks if you follow this pattern.
A Real-World Example...
In a current project I'm working on, I needed the ability to create various input form fields based upon information about the user who was visiting the page. Each user in the system belonged to one of a set of possible categories, and a number of the input form fields on this page were specific to a category. (For example, users in the category "Employee" might have a drop-down list from which they select their boss, whereas users in the category "Manager" would not have this drop-down list, but rather might have a couple of TextBoxes for information about their division and team.)
One particular data-entry page needed to display the appropriate input form fields, populate them with the user's current responses (if they had provided any), and then provide the user the ability to update (or save for the first time) their information. This involved three steps:
- Create the input form fields based upon the user visiting the page
- Populate the dynamic form fields with the user's values (if any)
- Save the user's responses upon the click of a "Save" button
To create the input form fields I create a method called LoadUI()
that I then have called from the page's Init
event handler. LoadUI()
's sole task is to create the dynamic controls based upon the current user's category. The pseudocode for this method looks as follows:
|
The code shown above starts by determining the user's type. This is performed by an application layer class with a method called GetUserType()
. The specifics of this method are not important; needless to say, it simply returns the user type of the currently logged on user. Next, I use a series of conditional statements to determine what set of controls to add. (In practice, I actually store the controls to add in a database, and in my LoadUI()
method I retrieve the set of controls to dynamically add based on the user's type. The benefit of this approach is that adjusting the custom input form fields for a particular user type is as simple as modifying the database - there's no need to touch any of the ASP.NET code. However, with my hard-coded approach shown above, any changes to the input forms for different types would require a modification of the LoadUI()
code and a recompilation/redeployment.)
On each page visit, be it the first visit to the page or on a postback, the LoadUI()
method will be invoked during the page's Initialization stage. Next, we need to have the user's current values (if they exist) displayed in the custom controls when the page is first visited. This is done in the Page_Load
event handler using the following code:
|
When loading the current values, we only do so on the first visit to the page (hence my check for Not Page.IsPostBack
). To load the current values, I first need to determine the user's type, and then load and populate the values of the dynamic form fields appropriately. In order to set the properties and call the methods of the dynamically created Web controls, I need to be able to reference the controls in the control hierarchy. In Working with Dynamically Created Controls we saw how to use the FindControl()
method to obtain a reference to a control in the control hierarchy. (Again, in practice, I don't use multiple conditionals, but rather determine what dynamic controls need to be populated based on information in the database. This allows me to forgo the conditionals and just have a couple of lines of code that queries the database for the values for the appropriate controls based on the user's type, and then finds those controls and assigns the user's values.)
The final step is to allow the user to update their information and save any changes back to the database. The Web page contains a Button Web and a corresponding Click
event handler. In the Click
event handler I again iterate through the dynamically added controls based on user type, and update the database accordingly.
|
Conclusion
In this article we saw how to work with dynamic controls so that their values and view state can be correctly persisted across postbacks. Dynamic controls, as evidenced in this articles and others on 4Guys, offer a great deal of capability, but using dynamic controls can be frustrating due to lost controls or view state if the controls are not added to the hierarchy appropriately. As we saw in this article, the general pattern to follow is:
- Add the dynamic controls on each page visit in the page's Initialization stage,
- Read/write the dynamic controls' properties and methods in the
Page_Load
event handler.
That's really all there is to it! Just make sure you follow this pattern, and dynamic controls become as easy to use as the static controls added in the page's HTML portion.
After posting this article an alert reader, Wessam Zeidan, emailed me sharing that dynamically loaded controls could be loaded in the Page_Load event handler if care was taken in the order with which the control was added to the Controls collection and when its properties were set. For a more in-depth discussion on this be sure to read my blog entries: Control Building and ViewState Lesson for the Day and Controls Building and ViewState Redux. |
Happy Programming!
发表评论
-
打包并自动安装SQL数据库
2007-08-05 13:04 585NET平台下WEB应用程序的 ... -
如何管理 Internet Explorer 6 中的 Cookie
2007-10-17 16:33 934本页 概要 更多信息 针对站点的 ... -
JSTL简介
2007-11-30 10:54 518JSTL是一个不断完善的开 ... -
实战web 2.0
2007-12-03 09:02 5092001年,是一个注定将被 ... -
Javascript 调用MSAgent
2007-12-20 12:57 746(本文假设您使用WindowsXP或Windows2000操作 ... -
webBrowser.execWB的完整说明
2008-01-14 14:09 782在不是js打开的页面上按window.close(), 会 ... -
js中的字符串处理函数
2008-01-15 12:41 7391.Asc(x),Chr(x):转换字符, ... -
打印机设置
2008-01-15 12:49 693// -- basic featuresfactory.pri ... -
eXtremeComponents介绍
2008-01-18 12:39 719eXtremeComponents介绍luckyhttp:// ... -
eXtremeComponents指南
2008-01-18 12:40 567extremeComponents指南 ... -
eXtremeComponents指南
2008-01-18 12:40 798extremeComponents指南 ... -
去掉打印时的页眉页脚
2008-01-24 09:44 738<scriptlanguage="JavaSc ... -
js常用资料
2008-01-24 09:46 941事件源对象 event.srcElement.t ... -
ScriptX printing: technical manual
2008-01-24 10:00 2413ScriptX printing: technical m ... -
Date函数与日期相差
2008-01-29 16:08 665<script language="java ... -
比较全的CSS cursor(鼠标样式)
2008-04-08 11:56 511十字准心 cursor:crosshair;手 cu ...
相关推荐
css自动换行css自动换行css自动换行css自动换行css自动换行css自动换行css自动换行css自动换行css自动换行
#### 知识点一:CSS自动换行的原理与方法 在Web开发中,实现文本的自动换行是一项常见的需求。本文档主要介绍了如何利用CSS来实现不同浏览器环境下的自动换行功能,并特别关注了对老旧浏览器如IE6和IE7的支持。 ##...
在CSS(层叠样式表)中,自动换行是一个关键的概念,它关乎着文本在不同屏幕尺寸和布局下的可读性和美观性。本篇将详细探讨CSS如何实现文本的自动换行,以及相关的技巧和最佳实践。 首先,我们来看一个基本的自动...
在网页设计中,"DIV CSS 图片自动换行"是一个常见的布局技巧,它涉及到CSS(层叠样式表)中的盒模型、布局模式以及响应式设计。这个技术主要用于展示一组图片,使得图片能够在页面中自动适应并换行排列,同时还可以...
在CSS布局中,自动换行是一个常见的需求,特别是在处理文本内容时。文本可能会包含各种字符类型,如连续的数字、英文字符,甚至不同语言的文字。本文主要探讨如何使用CSS来解决自动换行的问题,特别是针对IE和Fire...
在CSS(层叠样式表)中,自动换行是一个关键的概念,它涉及到如何处理文本在容器内的布局,特别是在有限的空间内。本篇文章将深入探讨如何使用CSS来控制文本的换行,尤其是对于div、p这样的块级元素以及表格中的文本...
正常文字的换行(亚洲文字和非亚洲文字)元素拥有默认的white-space:normal,当定义的宽度之后自动换行 html <div id=wrap>正常文字的换行(亚洲文字和非亚洲文字)元素拥有默认的white-space:normal,当定义</div> css #...
在许多应用场景中,例如聊天应用、编辑器或表单填写,我们需要实现文本框的自动换行功能,使得当用户输入的字符超过一行的宽度时,文本能够自动跳转到下一行,就像微信的输入框那样。这个特性对于提升用户体验至关...
### 表格自动换行与CSS属性详解 #### 标题解析:表格自动换行主义CSS属性 在网页设计和开发过程中,为了更好地控制表格布局和文本显示效果,使用CSS来实现表格内的文本自动换行是一项非常实用的技术。标题中的...
以上介绍的自动换行策略覆盖了从基本的文本换行到复杂布局中的自动调整,通过合理选择和组合这些CSS属性,开发者可以轻松应对不同场景下的自动换行需求,同时确保页面在各种浏览器中都能呈现出一致且美观的效果。...
CSS实现不换行/自动换行/文本超出隐藏显示省略号;自动换行,强制不换行,单行文本不换行多余文本显示省略号,第n行显示省略号,亲测有效。
若希望按钮内容自动换行,可以去掉这些替换,或者使用CSS的`word-break`属性控制单词断行。 2. CSS多列布局:使用`column-count`或`column-width`属性可以将按钮内容分到多列显示,达到自动换行的效果。但这种方法...
CSS自动换行解决方案 CSS(Cascading Style Sheets)是一种用于描述HTML文档样式的语言,以解决HTML文档的布局、样式、文字排版等问题。今天,我们将讨论如何使用 CSS 样式控制单元格内超长文本自动换行,并解决...
本文将详细讲解CSS中的两个关键属性:`word-wrap` 和 `word-break`,它们可以帮助我们解决自动换行和强制换行的问题。 首先,我们来看`word-wrap`属性。这个属性主要用于控制当一个单词或内容过长,超出了其容器的...
这将解决长串英文字母不能自动换行的问题和 TD 中汉字自动换行问题。 总结 在这里,我们讨论了如何使用 CSS 来控制 TD 中的换行。我们学习了强制不换行和强制换行的实现方法,并介绍了相关的属性和实例。