ExtAspNet应用技巧(六) - ViewState与动态创建控件
文章截图 - 更好的排版
问题描述
在上一篇文章中,首先在页面上以声明的方式定义个工具栏按钮,然后在后台通过编程的方式定义另一个按钮。
1. Asp.net页面声明:
<ext:Panel ShowBorder="false" ShowHeader="false" runat="server"> <ext:Toolbar ID="Toolbar1" runat="server"> <ext:Button ID="Button1" EnablePostBack="false" OnClientClick="window.open('default.aspx', '_blank');" Text="页面声明的按钮" runat="server"> </ext:Button> </ext:Toolbar> </ext:Panel>
2. 后台代码:
protected void Page_Load(object sender, EventArgs e) { ExtAspNet.Button btn = new Button(); btn.Text = "获取工具栏按钮个数"; btn.Click += new EventHandler(btn_Click); Toolbar1.Items.Add(btn); } private void btn_Click(object sender, EventArgs e) { Alert.Show("工具栏按钮个数:" + Toolbar1.Items.Count); }
3. 生成这样的页面:
后台我试着将动态添加的工具栏按钮放在第一个位置,如下所示
Toolbar1.Items.Insert(0, btn);
但是当我点击此按钮回发时,报错了:
解决思路
首先,我觉得可能是ExtAspNet内部出了问题,经过调试后发现是两个工具栏按钮的视图状态(ViewState)在回发时都丢失了。
那为什么通过 Items.Add 的方式就可以,而 Items.Insert 的方式ViewState就会丢失呢?
于是找来一个解析ViewState的小工具 ViewStateDecoder ,查看页面上ViewState:
从上面的截图中,我发现对两个按钮的ViewState的存取是按照顺序来的,那么会不会通过 Items.Insert 的方式导致视图顺序变化,后台读取时出错呢?
于是我在网上找到这篇文章:http://msdn.microsoft.com/en-us/library/ms972976.aspx
我截取了其中一段关于视图状态和动态添加控件的部分:
从这段描述中,可以得到如下结论:
- Page_Load是在页面加载视图之后调用的,而Page_Init在加载视图之前调用,因此动态添加控件最好的时机是在Page_Init中。
- 即使在Page_Load中动态添加的控件,其视图状态也能保持是因为在调用Controls.Add时会递归加载视图状态。
- 在Page_Load之后动态添加的控件不要改变现有控件的顺序,否则会导致视图状态不能正确加载(因为视图状态是按照其在父控件中的顺序标示的,正如上图所示)。
解决方案
有了以上几点做指导,解决方案也就是轻而易举的事了。我们大概有如下三种解决办法:
1. 第一种就是开篇提到的。在Page_Load中动态添加控件,但是不改变现有控件的顺序。
2. 在Page_Init中动态添加控件,这里你任意改变现有控件的顺序都行。
<ext:Panel ShowBorder="false" ShowHeader="false" runat="server"> <ext:Toolbar ID="Toolbar1" runat="server"> <ext:Button ID="Button1" EnablePostBack="false" OnClientClick="window.open('default.aspx', '_blank');" Text="页面声明的按钮" runat="server"> </ext:Button> </ext:Toolbar> </ext:Panel>
protected void Page_Init(object sender, EventArgs e) { ExtAspNet.Button btn = new Button(); btn.Text = "获取工具栏按钮个数"; btn.Click += new EventHandler(btn_Click); Toolbar1.Items.Insert(0, btn); } private void btn_Click(object sender, EventArgs e) { Alert.Show("工具栏按钮个数:" + Toolbar1.Items.Count); }
3. 动态创建所有的控件,这个比较适合在回发时动态创建控件(比如点击个按钮添加一个控件)。
<ext:Panel ShowBorder="false" ShowHeader="false" runat="server"> <ext:Toolbar ID="Toolbar1" runat="server"> </ext:Toolbar> </ext:Panel>
protected void Page_Load(object sender, EventArgs e) { ExtAspNet.Button btn = null; btn = new Button(); btn.Text = "页面声明的按钮"; btn.EnablePostBack = false; btn.OnClientClick = "window.open('default.aspx', '_blank');"; Toolbar1.Items.Add(btn); btn = new Button(); btn.Text = "获取工具栏按钮个数"; btn.Click += new EventHandler(btn_Click); Toolbar1.Items.Add(btn); } private void btn_Click(object sender, EventArgs e) { Alert.Show("工具栏按钮个数:" + Toolbar1.Items.Count); }
源代码在位于 http://extaspnet.codeplex.com/ 中的other\menu_dynamic2_run.aspx