Blazor中@oninput绑定循环索引越界问题求助
问题原因
这是Blazor中闭包捕获循环变量的典型问题:@for循环里的row和col是循环体外声明的变量,lambda表达式@(e => {this.updateDogSpeed(row, col, e);})捕获的是变量本身,而非循环迭代时的当前值。当循环结束后,row和col都会递增到dogList.Count(也就是8),所以任何输入框触发事件时,拿到的都是这两个变量的最终值。
解决方案(两种规范的Blazor原生写法)
方法一:循环内创建局部变量捕获当前值
在@for循环内部,为每一次迭代创建独立的局部变量,让lambda捕获这些局部变量的当前值:
<table class="table"> <thead> <!-- <tr> <th>Runs with</th> @foreach (var dog in dogList) { <th>@dog.name</th> } </tr> --> </thead> <tbody> <tr> <td style="width:120px;">Runs with ↗️ </td> @foreach(Dog dog in dogList) { <td style="width:120px;">@dog.name</td> } </tr> @for(var row = 0; row<dogList.Count; row++) { // 声明局部变量保存当前row值 var currentRow = row; <tr> <td style="width:120px;">@dogList[row].name</td> @for (var col = 0; col<dogList.Count; col++) { // 声明局部变量保存当前col值 var currentCol = col; <td style="width:120px;"> <input type="number" value="@dogSpeed[currentRow][currentCol]" @oninput="@(e => updateDogSpeed(currentRow, currentCol, e))" /> </td> } </tr> } </tbody> </table> @code { public void updateDogSpeed(int row, int col, ChangeEventArgs e) { if(double.TryParse(e.Value?.ToString(), out var newValue)) { dogSpeed[row][col] = newValue; // 可选:若UI未自动更新,手动触发状态变更 // StateHasChanged(); } Console.WriteLine($"row={row}, col={col}, e.Value={e.Value}"); } }
方法二:改用@foreach结合索引遍历
通过Select给每个元素绑定索引,彻底避免@for的闭包问题:
<table class="table"> <thead> <!-- <tr> <th>Runs with</th> @foreach (var dog in dogList) { <th>@dog.name</th> } </tr> --> </thead> <tbody> <tr> <td style="width:120px;">Runs with ↗️ </td> @foreach(Dog dog in dogList) { <td style="width:120px;">@dog.name</td> } </tr> @foreach(var rowItem in dogList.Select((dog, index) => new { Dog = dog, Row = index })) { <tr> <td style="width:120px;">@rowItem.Dog.name</td> @foreach(var colItem in dogList.Select((dog, index) => new { Dog = dog, Col = index })) { <td style="width:120px;"> <input type="number" value="@dogSpeed[rowItem.Row][colItem.Col]" @oninput="@(e => updateDogSpeed(rowItem.Row, colItem.Col, e))" /> </td> } </tr> } </tbody> </table> @code { public void updateDogSpeed(int row, int col, ChangeEventArgs e) { if(double.TryParse(e.Value?.ToString(), out var newValue)) { dogSpeed[row][col] = newValue; } Console.WriteLine($"row={row}, col={col}, e.Value={e.Value}"); } }
补充说明
- 两种方法都无需JavaScript,完全遵循Blazor原生规范。
- 用
double.TryParse做安全转换,避免输入非数字导致程序报错。 - 若修改数组后UI未自动更新,可手动调用
StateHasChanged()(比如当dogSpeed是值类型二维数组时,Blazor可能无法检测到内部元素变化)。
内容的提问来源于stack exchange,提问作者TomEberhard
相关产品推荐
相关产品推荐

