【问题标题】:C# dynamically created control issueC#动态创建控件问题
【发布时间】:2025-12-03 10:25:01
【问题描述】:

我在从动态创建的下拉列表中检索值时遇到问题。所有控件都在 Page_Init 部分中创建。列表项也是从列表项数组中添加的。 (控件的名称相同,因此应该可以访问视图状态以进行适当的设置。)

这是尝试检索值的函数:

protected void Eng98AssignmentComplete_Click(object sender, EventArgs e)
{
    String myID = "0";
    Page page = Page;
    Control postbackControlInstance = null;
    // handle the Button control postbacks
    for (int i = 0; i < page.Request.Form.Keys.Count; i++)
    {
        postbackControlInstance = page.FindControl(page.Request.Form.Keys[i]);
        //Response.Write(page.Request.Form.Keys[i].ToString());
        if (postbackControlInstance is System.Web.UI.WebControls.Button)
        {
            myID = Convert.ToString(
                postbackControlInstance.ID.Replace("button_", ""));
        }
    }
    String txtholder = "ctl00$ContentPlaceHolder$Eng098Instructors_" + myID;
    Response.Write("MYID: " + myID + "<br/>");
    DropDownList ddInstructorCheck = (DropDownList)Page.FindControl(txtholder);
    Response.Write("Instructor Selected: "
      + ddInstructorCheck.SelectedValue + "<br/>");
}

这是我得到的输出,无论选择了哪个讲师.....

MYID: 1_1
Instructor Selected: 0
ctl00$ContentPlaceHolder$Eng098Instructors_1_1

控件名称正确(已通过查看源代码验证)......

想法?

【问题讨论】:

    标签: c# asp.net dynamic-controls


    【解决方案1】:

    你需要做很多工作来构建这个花哨的字符串:

    ctl00$ContentPlaceHolder$Eng098Instructors_1_1

    这是您控件的客户端 ID,而不是服务器 ID。此代码在服务器端运行,因此您需要服务器 ID。要使用服务器 ID 进行控制,您需要这样做:

    ContentPlaceHolder.FindControl("Eng08Instructors_1_1");
    

    请注意,我没有查看页面,因为您的内容占位符创建了一个新的命名容器。

    此外,myID 变量的循环设置方式总是最终会在 Keys 集合中按住 last 按钮。为什么还要麻烦循环呢?


    根据您的 cmets,查找下拉列表 id 的更好方法如下:

    string id = ((Control)sender).ID.Replace("button_", "Eng098Instructors_");
    

    【讨论】:

    • 我不确定这是否符合您的想法。它通过页面上的键(所有,静态和动态控件),然后告诉我哪个用于调用回发,通过确定真/假(如果(postbackControlInstance 是 System.Web.UI.WebControls.Button )),按下哪个按钮。按下的按钮告诉我要更新哪个作业。或者我不明白......很有可能......
    • 对不起,这应该读作它也会保留最后一个按钮。现在修好了。但它绝对不会告诉你按下了哪些按钮。
    • 但它确实......这是工作代码......除了下拉菜单...... myID 最肯定地返回告诉我按下哪个按钮的 ID 的按钮部分。 if (postbackControlInstance is System.Web.UI.WebControls.Button) { myID = Convert.ToString(postbackControlInstance.ID.Replace("button_", ""));因为他们可以按下任意数量的按钮之一,所以我需要知道要询问哪个分配控制组以获取更新的值。 (我用过好几次了。。有没有更好的方法?)
    • 事实上,你的代码只有在按下最后一个按钮时才有效,我向你保证。如果您想知道按下了哪个按钮,只需使用事件的 sender 参数即可。那是引发事件的对象(按钮)。只需施放即可。
    【解决方案2】:

    为什么不将控件保存在类中的实例中,这样您就不必使用 FindControl?

    【讨论】:

      【解决方案3】:

      您是否还在回发期间重新创建控件?每个请求都必须重新创建动态生成/添加的控件,它们不会自动重新创建。

      【讨论】:

      • 动态创建控件的原因是因为应用程序是数据库驱动的。这意味着他们可以为每门课程添加/删除作业。这必须每次都以相同的方式动态构建,我绝对是在设置列表项值和文本。 (已验证),是的,每次创建页面(初始或回发)时,我都会在 Page_Init 函数中重新创建控件....我的值正确来自其他控件,而不是下拉...。
      • 如果应用程序是数据库驱动的,则使用数据驱动的命名容器,如中继器。
      【解决方案4】:

      你为什么不投射发件人?这应该是导致回发的按钮:

      string myId = "0";
      Button btn = sender as Button;
      if (btn != null)
          myId = btn.ID
      ...
      

      【讨论】:

      • 这里是整个部分。 for (int i = 0; i
      • 所以您找到了正确的 DropDownList,但 SelectedValue 始终相同,对吧?确保已启用 Viewstate。检查您是否在单击事件之前明确设置 SelectedValue。如果这样做,请先检查 Page.IsPostback。
      【解决方案5】:

      您需要执行类似的操作,因为 UniqueID 属性是 Request.Form 中的键。

              List<Button> buttons = new List<Button>();
              List<DropDownList> dropdowns = new List<DropDownList>();
              foreach (Control c in Controls)
              {
                  Button b = (c as Button);
                  if (b != null)
                  {
                      buttons.Add(b);
                  }
      
                  DropDownList d = (c as DropDownList);
                  if (d != null)
                  {
                      dropdowns.Add(d);
                  }
              }
      
              foreach (String key in Request.Form.Keys)
              {
                  foreach (Button b in buttons)
                  {
                      if (b.UniqueID == key)
                      {
                          String id = b.ID.Replace("button_", "");
                          String unique_id = "ctl00$ContentPlaceHolder$Eng098Instructors_" + id;
                          Response.Write("MYID: " + id + "<br/>");
      
                          foreach (DropDownList d in dropdowns)
                          {
                              if (d.UniqueID == unique_id)
                              {
                                  Response.Write("Instructor Selected: " + d.SelectedValue + "<br/>");
                                  break;
                              }
                          } 
                      }
                  }   
              }
      

      【讨论】:

        【解决方案6】:

        我不确定您为什么要在代码中生成控件(如果这样做,您仍然可以动态添加项目),但是生成控件的代码在这里可能会有很大帮助。我猜您没有设置列表项值,而只是设置了列表项文本。尝试查看您从 SelectedText 字段中获得的内容并发布您的控件创建函数。

        编辑: 在回复您对@Martin 帖子的评论时,您说“是的,每次创建页面(初始或回发)时,我都会在 Page_Init 函数中重新创建控件”。您在创建它们时是否也设置了选定的值?

        您也可以在页面上使用控件,即使您的数据来自数据库,控件本身也不必动态生成。

        【讨论】:

        • 从视图源: (注意:XXXXXXXXX 替换了其中的实际值)。所以这是设置。列表也被缩短了。
        • 如果我在 Page_Init 上设置了选定的值,我会收到一条错误消息,指出我不能在控件中拥有多个选定的值。如果我不这样做,那么它不会传递错误,但在回发时似乎没有保留值(我假设通过视图状态)......我已经检查了命名方案,它看起来是正确的,所以数据“应该”通过......
        【解决方案7】:

        这个怎么样?

        ((Button)sender).Parent.FindControl(myid)
        

        编辑:我误解了你的问题。但我认为你应该遵循页面生命周期。这是动态创建的控件的常见问题。

        我做了一些研究,这里有一些关于 Dynamically Created Controls 的信息可能会对你有所帮助...

        【讨论】:

        • 附件是迄今为止我读过的最好的文章!非常感谢。
        【解决方案8】:

        我有 2 次捕获……这是它们的含义。

        1.  I didn't clear the table I was adding to before re-creating the controls.
        

        显然我昨天对细节的关注已经关闭,我很确定控件的 ctlXX 领先者在回发时由于我重新创建控件的方式而有所不同。

        2.  I was assigning the same list to all the dropdownlist controls.  
        

        一旦我将每次创建时的查找称为下拉列表控件,一切正常。

        无论如何,它的价值......

        【讨论】: