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
posted @ 2009-08-11 12:35  三生石上(FineUI控件)  阅读(6521)  评论(12编辑  收藏  举报