Событие Blazor / razor onclick с параметром index - PullRequest
2 голосов
/ 10 июля 2020

У меня есть приведенный ниже код, но параметр индекса, который передается, когда я щелкаю элемент <tr>, всегда равен 9.

Это потому, что у меня есть 9 строк в таблице, которые передаются компоненту как данные. Итак, похоже, что индекс всегда является значением переменной 'i', которая была установлена ​​последней ... в этом случае значение i после последней строки в foreach l oop равно 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>
@code {
 
    private async Task  RowSelect(int rowIndex)
    {
        await ListRowSelected.InvokeAsync(rowIndex);
    }
}

Ответы [ 2 ]

2 голосов
/ 10 июля 2020

Общие

На самом деле ваша проблема связана с лямбдой, которая захватывает локальную переменную. См. Следующую симуляцию с консольным приложением для простоты.

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);
}

Будет выведено 3, 3, 3 трижды, а не 0, 1, 2.

Blazor

Цитируется из официальной документации о 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}.";
    }
}

Не используйте переменную al oop непосредственно в лямбда-выражении, например i в предыдущем примере для l oop пример. В противном случае одна и та же переменная используется всеми лямбда-выражениями, что приводит к использованию одного и того же значения во всех лямбда-выражениях. Всегда фиксируйте значение переменной в локальной переменной, а затем используйте ее. В предыдущем примере переменной l oop 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>
}
0 голосов
/ 10 июля 2020

Это происходит потому, что значение i не отображается на странице (как это было бы в MVC / Razor Pages), оно просто оценивается, когда вы запускаете событие. Вы не активируете событие, пока страница не будет отрисована, поэтому к этому моменту l oop будет завершено, поэтому значение для i всегда будет значением в конце l oop.

Есть несколько способов справиться с этим: либо используйте вместо него foreach l oop, если это подходит (что и делается в большинстве примеров документации Blazor), либо объявите локальную переменную внутри l oop:

@for(int i=0;i< ListData.DataView.Table.Rows.Count; i++)
{
   int local_i=i;

    // Now use local_i instead of i in the code inside the for loop
}

Здесь хорошее обсуждение этого в репозитории Blazor Docs , которое объясняет проблему следующим образом:

Проблема обычно встречается в обработчиках событий и выражениях привязки. Мы должны объяснить, что в for l oop у нас есть только одна итерационная переменная, а в foreach у нас есть новая переменная для каждой итерации. Мы должны объяснить, что содержимое HTML отображается при выполнении for / foreach l oop, но обработчики событий вызываются позже. Вот пример кода, демонстрирующий одно неправильное и два хороших решения.

Все это особенно сбивает с толку, если вы переходите в Blazor из фона страницы MVC / Razor, где for - это нормальное поведение. Разница в том, что в MVC значение i фактически записывается в html на странице, и поэтому будет отличаться для каждой строки таблицы в вашем примере.

Согласно проблема, указанная выше, и ответ @Fat Man No Neck, причина root заключается в различиях в поведении циклов for и foreach с лямбда-выражениями. Это не ошибка Blazor, просто C# работает.

...