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

Cod*_*eek 14 c# razor-pages blazor-server-side

我有下面的代码,但是当我单击该<tr>元素时传递的索引参数始终为 9。

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

我的代码中的问题是什么,没有i为每行 onclick 设置值。

    <table border="1">

        @for(int i=0;i< ListData.DataView.Table.Rows.Count; i++)
        {
            <tr @onclick="(() => RowSelect(i))">
                @foreach (ModelColumn col in ListData.ListColumns)
                {
                    <td>@ListData.DataView.Table.Rows[i][col.Name]</td>
                }
            </tr>
        }

    </table>
Run Code Online (Sandbox Code Playgroud)
@code {
 
    private async Task  RowSelect(int rowIndex)
    {
        await ListRowSelected.InvokeAsync(rowIndex);
    }
}
Run Code Online (Sandbox Code Playgroud)

xpo*_*ort 20

一般的

实际上你的问题是关于捕获局部变量的 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);
}
Run Code Online (Sandbox Code Playgroud)

它将输出3, 3, 3三次而不是 0, 1, 2.

布拉佐尔

引用官方文档中有关EventCallback的内容:

<h2>@message</h2>

@for (var i = 1; i < 4; i++)
{
    var buttonNumber = i;

    <button class="btn btn-primary"
            @onclick="@(e => UpdateHeading(e, buttonNumber))">
        Button #@i
    </button>
}

@code {
    private string message = "Select a button to learn its position.";

    private void UpdateHeading(MouseEventArgs e, int buttonNumber)
    {
        message = $"You selected Button #{buttonNumber} at " +
            $"mouse position: {e.ClientX} X {e.ClientY}.";
    }
}
Run Code Online (Sandbox Code Playgroud)

不要直接在 lambda 表达式中使用循环变量,例如i前面的 for 循环示例。否则,所有 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>
}
Run Code Online (Sandbox Code Playgroud)