Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 通过编码创建事件_C#_.net - Fatal编程技术网

C# 通过编码创建事件

C# 通过编码创建事件,c#,.net,C#,.net,我有一个选中列表框和一个面板。它们都是由代码创建的。现在我想创建一个事件,通过选中和取消选中checkedListBox项中的一项,该面板将启用或禁用。我有以下代码,但它不工作,并在运行时抛出异常 CheckedListBox chlb = new CheckedListBox(); for (int i = 0; i < dr.Count(); i++) { chlb.Items.Add( dr[i]["Value_Name"].ToString()); if ((boo

我有一个选中列表框和一个面板。它们都是由代码创建的。现在我想创建一个事件,通过选中和取消选中checkedListBox项中的一项,该面板将启用或禁用。我有以下代码,但它不工作,并在运行时抛出异常

CheckedListBox chlb = new CheckedListBox();
for (int i = 0; i < dr.Count(); i++)
{
    chlb.Items.Add( dr[i]["Value_Name"].ToString());
    if ((bool)dr[i]["HasText"] == true)
    {
        Panel pnltxt = new Panel();
        pnltxt.Size = new Size(630, 30);
        chlb.SelectedIndexChanged += (s, argx) => pnltxt.Enabled =
           (chlb.GetItemCheckState(i).ToString().Trim() == "Unchecked" ? false : true);
    }
}
CheckedListBox chlb=新的CheckedListBox();
对于(int i=0;ipnltxt.Enabled=
(chlb.GetItemCheckState(i).ToString().Trim()=“未检查”?false:true);
}
}
错误消息是:

其他信息:InvalidArgument=值“7”对“索引”无效。 +chlb.GetItemCheckState(i)'chlb.GetItemCheckState(i)'引发了类型为'System.ArgumentOutOfRangeException'System.Windows.Forms.CheckState{System.ArgumentOutOfRangeException}的异常

您能帮助我如何为该活动编写正确的代码吗。

将您的代码更改为

if ((bool)dr[i]["HasText"]) {
    Panel pnltxt = new Panel();
    pnltxt.Size = new Size(630, 30);
    int index = i;
    chlb.SelectedIndexChanged += (s, argx) => pnltxt.Enabled =
        chlb.GetItemCheckState(index).ToString().Trim() != "Unchecked";
}
它被称为访问修改的闭包,并且与闭包的作用域规则有关

看看

此消息表示您正在使用的变量来自 枚举可能会发生更改,而不是您所期望的 在将要使用它的时候。这不会抛出编译器 错误

在 枚举(对于每个循环)是创建一个本地副本并使用它


因此,我在
index
中创建了变量
I
的本地副本,并使用了它。

您的问题在于lambda表达式和闭包

当您创建lambda表达式(就像您使用事件处理程序一样)并且它引用外部变量时,编译器需要创建一个包含该变量的闭包,以便lambda函数可以使用它。因此,这里:

for (int i=0; ......)
{
     //...
     chlb.SelectedIndexChanged += (s, argx) => pnltxt.Enabled =
         (chlb.GetItemCheckState(i).ToString().Trim() == "Unchecked" ? false : true);
     //..........................^
}
lambda表达式使用循环变量
i
,它必须有一个包含它的闭包,以便在执行函数时使用它。但问题是,在lambda表达式被分配给事件处理程序时,它没有得到变量的副本,它实际上引用了与正在循环的变量相同的变量。那有什么问题?当执行lambda表达式(即事件发生)时,
i
的值就是它在循环结束时的值!也就是说,
dr.Count()
(大概是
7

解决方案是将变量复制到循环中(如@astander的回答中所示),这样它将关闭变量的副本,该副本将保留附加事件处理程序时的值

因此:


让我猜猜,
dr.Count()
7
?这并没有破坏任何东西,但您确实不应该将“Unchecked”作为字符串进行比较。只需与CheckedState.Unchecked进行比较,并避免字符串问题。为了清楚起见,请更改
chlb.GetItemCheckState(i).ToString().Trim()=“Unchecked”?false:true
chlb.GetItemCheckState(i)!=CheckState.Unchecked
您应该解释更改了什么以及更改的重要性。这篇文章,没有解释,是一个低质量的回答。@Servy,我正在寻找一个像样的链接/文章来提供给OPIt。在这个网站上,仅仅链接到一个问题的解决方案是不合适的。您的答案应该回答问题,而不仅仅是链接到其他地方的答案。@Servy,我已经根据您的请求更新了答案。我已经编辑了答案,简化了部分
pnltxt.Enabled=(条件?false:true)
,并将其更改为
pnltxt.Enabled=!条件
并删除了
==true
部分。
for (int i=0; ......)
{
     int copyOfi = i;    // A new variable will get created every iteration!
     //...
     chlb.SelectedIndexChanged += (s, argx) => pnltxt.Enabled =
         (chlb.GetItemCheckState(copyOfi).ToString().Trim() == "Unchecked" ? false : true);
     //..........................^
     // And this will close to include only the `copyOfi` we created in this iteration
}