Asp.net:如何添加引用动态创建元素的事件处理程序

我有一个 asp.net 程序,可以创建一个简单的调查表供用户回答。大多数问题使用一个下拉列表,其答案分数为 1-5(坏-好),我正在尝试向下拉列表对象添加一个事件处理程序,以便仅在用户选择 1 到 1 之间的分数时才启用评论框2.


然而,当我为事件处理程序添加委托 lambda 调用时,而不是每个下拉列表影响它们自己对应的注释框,它们似乎都只指向添加的最后一个(并且它们工作一次,然后没有更多,只有最后一个 ddl 继续具有预期的行为)。


我的代码:


   //Called from Page_Load

   private void PopulateSurvey()

   {

        btnSubmit.Enabled = true;

        List<Question> questions = (from p in context.Questions

                                    join q in context.Survey_Questions on p.ID equals q.QuestionID

                                    where q.SurveyID == surveyid

                                    select p).ToList();

        Table tbl = new Table();

        tbl.Width = Unit.Percentage(100);

        TableRow tr;

        TableCell tc;

        TableCell tc1;

        TableCell tc2;

        TextBox txt;

        CheckBox cbk;

        DropDownList ddl = new DropDownList();


        foreach (Question q in questions)

        {


            if (q.Division.Equals("General") || q.Division.Equals(ddlDivisions.SelectedValue.ToString()))

            {

                tr = new TableRow();

                tc = new TableCell();

                tc.Width = Unit.Percentage(55);

                tc.Text = q.Text;

                tc.Attributes.Add("id", q.ID.ToString());

                tr.Cells.Add(tc);

                tc = new TableCell();


                if (q.QuestionType.ToLower() == "singlelinetextbox")

                {

                    txt = new TextBox();

                    txt.ID = "txt_" + q.ID;

                    //txt.Width = Unit.Percentage(40);

                    tc.Controls.Add(txt);

                }


首先想到的是,事件处理程序可能会保留引用本身,而不是每个问题创建的孤立对象,因此所有事件处理程序最终都具有相同的 tc1 和 tc2 引用,因此只有最后一个对象?是这样吗,如果是这样,我该如何解决?


慕工程0101907
浏览 114回答 1
1回答

摇曳的蔷薇

你的问题在这一行:ddl.SelectedIndexChanged&nbsp;+= &nbsp;&nbsp;&nbsp;&nbsp;(sender,&nbsp;e)&nbsp;=>&nbsp;ScoreChanged(sender,&nbsp;e,&nbsp;tc1,tc2,&nbsp;ddl.SelectedIndex);这里有两件事很重要:您正在使用匿名方法调用ScoreChanged.您正在传递tc1和tc2作为ScoreChanged方法的参数。您已在代码块的开头、循环外定义了这些变量。在这种情况下,神奇的词是闭包。由于tc1和tc2是在匿名方法的范围之外定义的,因此它们变成了闭包。这意味着在您定义方法时将没有值,但在您调用它时。由于您不断覆盖foreach循环中变量的值,因此在调用时这些变量将具有循环最后一次迭代的值。解决方案很简单:在循环内声明变量。这将为 的每次迭代创建一个新的闭包foreach:TableRow tr;TableCell tc;TextBox txt;CheckBox cbk;foreach (Question q in questions){&nbsp; &nbsp; TableCell tc1;&nbsp; &nbsp; TableCell tc2;&nbsp; &nbsp; DropDownList ddl; //Don't forget to include ddl, since you are using its selected index&nbsp; &nbsp; //...更一般的注意事项:不要在 C# 中的方法的开头执行这样的“声明”块。第一次使用时声明变量(除非有充分的理由不这样做,例如您希望它成为闭包的一部分)。这有很多很好的理由,而您只是体验过其中的一个。另一种情况是,当您将部分代码转换为具有 Visual Studio 重构功能的方法时,您会将预先声明的变量作为ref参数传递。这些是最明显的原因。还有更多。
打开App,查看更多内容
随时随地看视频慕课网APP