2011-01-28 112 views
5

我想创建一个复合ASP.NET控件,让你建立一个可编辑的控件集合。ASP.NET动态控件计数(创建控件,你去)

我的问题是,当我按下添加或回发按钮(除了要回发表单之外什么都不做),任何输入到文本框中的值都会丢失。

当控件的数量在回发之间发生变化时,我无法使它工作。我需要基本上能够在控制生命周期的两个不同时间重新创建控制树,具体取决于视图状态属性ControlCount

该测试可用于重现该问题:

public class AddManyControl : CompositeControl 
{ 
    protected override void OnLoad(EventArgs e) 
    { 
     base.OnLoad(e); 
     EnsureChildControls(); 
    } 

    protected override void CreateChildControls() 
    { 
     var count = ViewState["ControlCount"] as int? ?? 0; 

     for (int i = 0; i < count; i++) 
     { 
      var div = new HtmlGenericControl("div"); 
      var textBox = new TextBox(); 
      textBox.ID = "tb" + i; 
      div.Controls.Add(textBox); 
      Controls.Add(div); 
     } 

     ViewState["ControlCount"] = count; 

     var btnAdd = new Button(); 
     btnAdd.ID = "Add"; 
     btnAdd.Text = "Add text box"; 
     btnAdd.Click += new EventHandler(btnAdd_Click); 
     Controls.Add(btnAdd); 

     var btnPostBack = new Button(); 
     btnPostBack.ID = "PostBack"; 
     btnPostBack.Text = "Do PostBack"; 
     Controls.Add(btnPostBack); 
    } 

    void btnAdd_Click(object sender, EventArgs e) 
    { 
     ViewState["ControlCount"] = (int)ViewState["ControlCount"] + 1; 
    } 

    protected override void OnPreRender(EventArgs e) 
    { 
     base.OnPreRender(e); 
     // If I remove this RecreateChildControls call 
     // the collection lags behind each postback 
     // because the count is incremented in the btnAdd_Click event handler 
     // however, the values are not lost between postbacks 
     RecreateChildControls(); 
    } 
} 

回答

5

如果你想玩ASP.NET的自定义控件,你必须发挥它的规则和它的挑剔!当您开始在自定义控件中使用OnPreRender时,您会发现90%的时间都处于错误的轨道上。

一般来说,使用ViewState的最好方法是声明一个由它支持的属性,就像标准的ASP.NET控件一样(.NET Reflector多年来一直是我的老师!)。这样,它将在事件的生命周期中被自然地读取和保存。

这里,似乎你想要做什么,很自然的一个代码,没有任何诀窍:

public class AddManyControl : CompositeControl 
{ 
    private void AddControl(int index) 
    { 
     var div = new HtmlGenericControl("div"); 
     var textBox = new TextBox(); 
     textBox.ID = "tb" + index; 
     div.Controls.Add(textBox); 
     Controls.AddAt(index, div); 
    } 

    protected override void CreateChildControls() 
    { 
     for (int i = 0; i < ControlsCount; i++) 
     { 
      AddControl(i); 
     } 

     var btnAdd = new Button(); 
     btnAdd.ID = "Add"; 
     btnAdd.Text = "Add text box"; 
     btnAdd.Click += new EventHandler(btnAdd_Click); 
     Controls.Add(btnAdd); 

     var btnPostBack = new Button(); 
     btnPostBack.ID = "PostBack"; 
     btnPostBack.Text = "Do PostBack"; 
     Controls.Add(btnPostBack); 
    } 

    private int ControlsCount 
    { 
     get 
     { 
      object o = ViewState["ControlCount"]; 
      if (o != null) 
       return (int)o; 

      return 0; 
     } 
     set 
     { 
      ViewState["ControlCount"] = value; 
     } 
    } 

    void btnAdd_Click(object sender, EventArgs e) 
    { 
     int count = ControlsCount; 
     AddControl(count); 
     ControlsCount = count + 1; 
    } 
} 
+0

+1为解决方案,它工作正常,我很好奇 – 2011-01-30 13:45:36

-2

我相信你必须控制加入到视图状态。

+0

没有,它不喜欢的工作。这是别的。某些生命周期事件没有在第二次运行(因为正在重新创建控制树)。 – 2011-01-29 09:35:06