C# 带索引参数的Blazor/razor onclick事件

C# 带索引参数的Blazor/razor onclick事件,c#,razor-pages,blazor-server-side,C#,Razor Pages,Blazor Server Side,我有下面的代码,但单击元素时传递的索引参数始终为9 这是因为表中有9行作为数据传递给组件。 所以看起来索引总是最后设置的变量“i”的值。。。在这种情况下,foreach循环中最后一行之后的i的值是9,因此在单击表中的所有行时,我得到的索引参数是9 我的代码中有什么问题没有设置每行onclick的i值 @for(int i=0;i

我有下面的代码,但单击
元素时传递的索引参数始终为9

这是因为表中有9行作为数据传递给组件。 所以看起来索引总是最后设置的变量“i”的值。。。在这种情况下,foreach循环中最后一行之后的i的值是9,因此在单击表中的所有行时,我得到的索引参数是9

我的代码中有什么问题没有设置每行onclick的
i


@for(int i=0;i
@code{
专用异步任务行选择(int行索引)
{
wait ListRowSelected.InvokeAsync(rowIndex);
}
}
概述 实际上,您的问题是关于捕获局部变量的lambda。为了简单起见,请参阅下面的控制台应用程序模拟

class Program
{
    static void Main(string[] args)
    {
        Action[] acts = new Action[3];

        for (int i = 0; i < 3; i++)
            acts[i] = (() => Job(i));

        foreach (var act in acts) act?.Invoke();
    }

    static void Job(int i) => Console.WriteLine(i);
}
不要在lambda表达式中直接使用循环变量,例如前面for循环示例中的
i
。否则,所有lambda表达式将使用相同的变量,这将导致在所有lambda中使用相同的值。始终在局部变量中捕获变量的值,然后使用它。在前面的示例中,循环变量i被分配给
buttonNumber

因此,您需要为
i
制作一个本地副本,如下所示

@for(int i=0;i< ListData.DataView.Table.Rows.Count; i++)
{
   int buffer=i;
    <tr @onclick="(() => RowSelect(buffer))">
        @foreach (ModelColumn col in ListData.ListColumns)
        {
            <td>@ListData.DataView.Table.Rows[i][col.Name]</td>
        }
    </tr>
}
@for(int i=0;i
发生这种情况是因为
i
的值没有呈现到页面中(就像在MVC/Razor页面中一样),它只是在触发事件时进行计算。在页面呈现之前,您不会触发事件,因此在该点循环将完成,因此
i
的值将始终是循环结束时的值

有两种方法可以解决这个问题,或者在合适的情况下使用
foreach
循环(大多数Blazor文档示例都是这样做的),或者在循环中声明一个局部变量:

@for(int i=0;i
有一个例子,它解释了问题如下:

问题通常出现在事件处理程序和绑定表达式中。 我们应该解释一下,在
for
循环中,我们只有一个迭代变量 在
foreach
中,每个迭代都有一个新的变量。我们应该 解释在执行
for
/
foreach
循环时呈现HTML内容 已执行,但稍后将调用事件处理程序。下面是一个示例代码 演示一个错误和两个好的解决方案

如果您是从MVC/Razor页面背景来到Blazor,使用
for
是一种正常行为,那么这一切都会让您感到特别困惑。不同之处在于,在MVC中,
i
的值实际上被写入页面上的html中,因此在您的示例中,表的每一行都会有所不同


根据上面链接的问题和@Fat Man No Neck的回答,这一问题的根本原因在于
for
foreach
循环与lambda表达式的行为差异。这不是Blazor bug,这只是C#的工作方式。

在将计数器传递给lambda之前,您需要缓冲
i
。非常感谢!!!它是有效的。。。我需要定义一个int然后每次赋值的确切原因是什么?谢谢,它确实有效…明白了!“我不知道我需要在传递给lambda的时候这样做。@Codegeek:有关详细信息,请阅读此内容。”。
@for(int i=0;i< ListData.DataView.Table.Rows.Count; i++)
{
   int buffer=i;
    <tr @onclick="(() => RowSelect(buffer))">
        @foreach (ModelColumn col in ListData.ListColumns)
        {
            <td>@ListData.DataView.Table.Rows[i][col.Name]</td>
        }
    </tr>
}