vip*_*tti 2 asp.net viewstate controls dynamic
ASP.NET页面ViewState似乎很难跟上动态删除的控件及其中的值.
我们以下面的代码为例:
ASPX:
<form id="form1" runat="server">
<div>
<asp:Panel runat="server" ID="controls" />
</div>
</form>
Run Code Online (Sandbox Code Playgroud)
CS:
protected void Page_Init(object sender, EventArgs e) {
Button b = new Button();
b.Text = "Add";
b.Click +=new EventHandler(buttonOnClick);
form1.Controls.Add(b);
Button postback = new Button();
postback.Text = "Postback";
form1.Controls.Add(postback);
}
protected void Page_Load(object sender, EventArgs e) {
if (ViewState["controls"] != null) {
for (int i = 0; i < int.Parse(ViewState["controls"].ToString()); i++) {
controls.Controls.Add(new TextBox());
Button remove = new Button();
remove.Text = "Remove";
remove.Click +=new EventHandler(removeOnClick);
controls.Controls.Add(remove);
controls.Controls.Add(new LiteralControl("<br />"));
}
}
}
protected void removeOnClick(object sender, EventArgs e) {
Control s = sender as Control;
//A hacky way to remove the components around the button and the button itself
s.Parent.Controls.Remove(s.Parent.Controls[s.Parent.Controls.IndexOf(s) + 1]);
s.Parent.Controls.Remove(s.Parent.Controls[s.Parent.Controls.IndexOf(s) - 1]);
s.Parent.Controls.Remove(s.Parent.Controls[s.Parent.Controls.IndexOf(s)]);
ViewState["controls"] = (int.Parse(ViewState["controls"].ToString()) - 1).ToString();
}
protected void buttonOnClick(object sender, EventArgs e) {
if (ViewState["controls"] == null)
ViewState["controls"] = "1";
else
ViewState["controls"] = (int.Parse(ViewState["controls"].ToString()) + 1).ToString();
controls.Controls.Add(new TextBox());
}
Run Code Online (Sandbox Code Playgroud)
然后,假设您创建了4个控件并插入以下值:
[ 1 ] [ 2 ] [ 3 ] [ 4 ]
Run Code Online (Sandbox Code Playgroud)
我们要删除第二个控件; 删除第二个控件后输出为:
[ 1 ] [ 3 ] [ 4 ]
Run Code Online (Sandbox Code Playgroud)
这就是我们想要的.不幸的是,在随后的PostBack中,列表变为:
[ 1 ] [ ] [ 3 ]
Run Code Online (Sandbox Code Playgroud)
所以,我的问题是,为什么会发生这种情况?据我所知,ViewState应该保存控件的属性与其索引相关,而不是实际控件.
几件事.是否通过其ID或索引加载控件取决于ViewStateModeById属性.默认情况下,它为false(表示按索引加载).
但是,文本框的处理方式不同.除非它们被禁用或不可见,否则它们的视图状态不包含输入值.text属性会被使用其ID的已发布值覆盖.由于您不管理文本框ID,因此会发生这种情况.
添加四个控件后,您有四个文本框:ctrl0,ctrl1,ctrl2和ctrl3,其值分别为1,2,3和4.
接下来,删除ctrl1框,客户端获取三个框:ctrl0,ctrl2和ctrl3,具有相应的值.现在,当您进行任何回发时,这三个值将以ctrl0 = 1&ctrl2 = 3&ctrl3 = 4的形式提交.
然后,在Page_Load上,创建三个控件,这次:ctrl0,ctrl1,ctrl2没有值.
Framework调用LoadRecursive来加载视图状态,然后调用ProcessPostData来分配输入值.它看到提交的ctrl0和ctrl2,找到具有相同id的控件并为它们赋值1和3.它没有找到ctrl3,所以它会跳过它.剩下的ctrl1只执行任何值的w/o.
例如,考虑这个解决方案(不是最好的):
protected void Page_Init(object sender, EventArgs e)
{
Button b = new Button();
b.Text = "Add";
b.Click += new EventHandler(buttonOnClick);
form1.Controls.Add(b);
Button postback = new Button();
postback.Text = "Postback";
form1.Controls.Add(postback);
}
protected void Page_Load(object sender, EventArgs e)
{
if (ViewState["controls"] != null)
{
List<string> ids = (List<string>)ViewState["controls"];
for (int i = 0; i < ids.Count; i++)
{
TextBox textbox = new TextBox();
textbox.ID = string.Format("txt_{0}", ids[i]);
textbox.Text = textbox.ID;
controls.Controls.Add(textbox);
Button remove = new Button();
remove.Text = "Remove";
remove.Click += new EventHandler(removeOnClick);
remove.ID = ids[i];
controls.Controls.Add(remove);
controls.Controls.Add(new LiteralControl("<br />"));
}
}
}
protected void removeOnClick(object sender, EventArgs e)
{
Control btn = sender as Control;
List<string> ids = (List<string>)ViewState["controls"];
ids.Remove(btn.ID);
//A hacky way to remove the components around the button and the button itself
btn.Parent.Controls.Remove(btn.Parent.Controls[btn.Parent.Controls.IndexOf(btn) + 1]);
btn.Parent.Controls.Remove(btn.Parent.Controls[btn.Parent.Controls.IndexOf(btn) - 1]);
btn.Parent.Controls.Remove(btn);
ViewState["controls"] = ids;
}
protected void buttonOnClick(object sender, EventArgs e)
{
List<string> ids;
if (ViewState["controls"] == null)
ids = new List<string>();
else
ids = (List<string>)ViewState["controls"];
string id = Guid.NewGuid().ToString();
TextBox textbox = new TextBox();
textbox.ID = string.Format("txt_{0}", id);
textbox.Text = textbox.ID;
controls.Controls.Add(textbox);
Button remove = new Button();
remove.Text = "Remove";
remove.Click += new EventHandler(removeOnClick);
remove.ID = id;
controls.Controls.Add(remove);
controls.Controls.Add(new LiteralControl("<br />"));
ids.Add(id);
ViewState["controls"] = ids;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5002 次 |
| 最近记录: |