Blazor按钮点击处理器无法保留参数值问题求助
问题分析
这是Blazor开发中常见的闭包变量引用捕获问题:你绑定的@onclick lambda表达式()=> {ButtonClicked(i);},捕获的是循环变量i的引用而非每次循环时的具体值。当循环结束后,i的最终值为5(循环条件i<6,最后一次循环后i自增到6才退出),所以所有按钮点击时都会调用ButtonClicked(5)。
解决方案
方法1:循环内创建局部变量保存当前值
在每次循环中,把当前i的值赋值给一个局部变量,让lambda捕获这个局部变量的副本:
@page "/" <PageTitle>Index</PageTitle> <div>Number Clicked is @NumberClicked</div> <table> @for(int i=0; i< 6; i++){ // 新增局部变量,保存当前循环的i值 var currentNum = i; <tr><td><button type="button" class="btn btn-link" @onclick="()=> {ButtonClicked(currentNum);}">@i</button></td></tr> } </table> @code { public string NumberClicked { get; set; } public void ButtonClicked(int i) { NumberClicked = i.ToString(); } }
方法2:改用foreach循环遍历集合
将循环范围转为集合(比如Enumerable.Range(0,6)),foreach循环在C# 5+版本中,每次迭代的变量都是独立实例,lambda会自动捕获当前迭代的变量值:
@page "/" <PageTitle>Index</PageTitle> <div>Number Clicked is @NumberClicked</div> <table> @foreach(var num in Enumerable.Range(0,6)){ <tr><td><button type="button" class="btn btn-link" @onclick="()=> {ButtonClicked(num);}">@num</button></td></tr> } </table> @code { public string NumberClicked { get; set; } public void ButtonClicked(int i) { NumberClicked = i.ToString(); } }
原理补充
- for循环的变量
i是在循环外部声明的,整个循环过程中同一个变量被反复赋值,lambda捕获的是这个变量的内存引用,因此所有按钮最终都会指向变量的最终值。 - 局部变量
currentNum在每次循环时都会生成新的实例,lambda捕获的是当前循环的变量副本,每个按钮对应独立的变量值。 - foreach循环的迭代变量在C# 5及以后版本中,每次迭代都会创建新的变量实例,天然避免了闭包引用捕获的问题。
内容的提问来源于stack exchange,提问作者Aamir
相关产品推荐
相关产品推荐

