为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
慕工程0101907 2021-06-30 21:10:02
我有一个 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 引用,因此只有最后一个对象?是这样吗,如果是这样,我该如何解决?
查看完整描述

1 回答

?
摇曳的蔷薇

TA贡献1793条经验 获得超6个赞

你的问题在这一行:

ddl.SelectedIndexChanged +=
    (sender, e) => ScoreChanged(sender, e, tc1,tc2, ddl.SelectedIndex);

这里有两件事很重要:

  • 您正在使用匿名方法调用ScoreChanged.

  • 您正在传递tc1tc2作为ScoreChanged方法的参数。您已在代码块的开头、循环定义了这些变量。

在这种情况下,神奇的词是闭包。由于tc1tc2是在匿名方法的范围之外定义的,因此它们变成了闭包。这意味着在您定义方法时将没有值,但在您调用它时。由于您不断覆盖foreach循环中变量的值,因此在调用时这些变量将具有循环最后一次迭代的值。

解决方案很简单:在循环声明变量。这将为 的每次迭代创建一个新的闭包foreach

TableRow tr;

TableCell tc;

TextBox txt;

CheckBox cbk;


foreach (Question q in questions)

{

    TableCell tc1;

    TableCell tc2;

    DropDownList ddl; //Don't forget to include ddl, since you are using its selected index

    //...

更一般的注意事项:不要在 C# 中的方法的开头执行这样的“声明”块。第一次使用时声明变量(除非有充分的理由不这样做,例如您希望它成为闭包的一部分)。这有很多很好的理由,而您只是体验过其中的一个。另一种情况是,当您将部分代码转换为具有 Visual Studio 重构功能的方法时,您会将预先声明的变量作为ref参数传递。这些是最明显的原因。还有更多。


查看完整回答
反对 回复 2021-07-03
  • 1 回答
  • 0 关注
  • 112 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信