MudRating点击时SelectedValueChanged触发两次问题排查与解决
MudRating二次触发SelectedValueChanged的问题分析与解决
问题场景
采用三层结构开发:
- 主Razor文件:
<Rating @bind-Value="@Model.RoiRating" Descriptions="@Rating.RoiDescriptions"/>
- Rating.razor:
<MudRating SelectedValue="Value" SelectedValueChanged="OnSelectedValueChanged" HoveredValueChanged="OnHoveredValueChanged" /> <MudText Typo="Typo.subtitle2" Class="deep-purple-text mt-2">@RatingText</MudText>
- Rating.razor.cs:
public partial class Rating { public static string[] RoiDescriptions = new[] { "Rate the ROI", "Damaging", "Negative", "Ineffective", "Helpful", "Awesome!" }; [Parameter] public string[] Descriptions { get; set; } = RoiDescriptions; [Parameter] public int Value { get; set; } [Parameter] public EventCallback<int> ValueChanged { get; set; } private int? _activeValue; private void OnHoveredValueChanged(int? val) => _activeValue = val; private string RatingText { get { if (_activeValue is null or < 1 or > 5) return Descriptions[0]; return Descriptions[_activeValue.Value]; } } }
点击第3颗星时,调试器显示两次调用:
OnSelectedValueChanged(3) OnSelectedValueChanged(0)
问题原因
- Rating组件未实现
OnSelectedValueChanged方法,无法将MudRating的新值同步到上层绑定的Value参数。 - 当MudRating触发
SelectedValueChanged(3)后,组件因状态变化重新渲染,但上层的Model.RoiRating(即Rating组件的Value参数)仍为原始值(比如0)。 - 重新渲染时,MudRating的
SelectedValue被重置为Value的原始值0,因此再次触发SelectedValueChanged(0)。
解决方法
核心是通过内部状态同步值,并正确触发ValueChanged回调更新上层绑定数据,同时遵循Blazor参数不可直接修改的规则。
修改后的Rating.razor.cs
public partial class Rating { public static string[] RoiDescriptions = new[] { "Rate the ROI", "Damaging", "Negative", "Ineffective", "Helpful", "Awesome!" }; [Parameter] public string[] Descriptions { get; set; } = RoiDescriptions; [Parameter] public int Value { get; set; } [Parameter] public EventCallback<int> ValueChanged { get; set; } private int? _activeValue; // 初始化时同步上层Value到内部状态 protected override void OnInitialized() { _activeValue = Value; } // 上层参数更新时同步内部状态 protected override void OnParametersSet() { if (_activeValue != Value) { _activeValue = Value; } } // 处理MudRating的值变化 private async Task OnSelectedValueChanged(int val) { _activeValue = val; // 通知上层更新绑定数据 await ValueChanged.InvokeAsync(val); } private void OnHoveredValueChanged(int? val) => _activeValue = val; private string RatingText { get { if (_activeValue is null or < 1 or > 5) return Descriptions[0]; return Descriptions[_activeValue.Value]; } } }
修改后的Rating.razor
<MudRating SelectedValue="@_activeValue" SelectedValueChanged="OnSelectedValueChanged" HoveredValueChanged="OnHoveredValueChanged" /> <MudText Typo="Typo.subtitle2" Class="deep-purple-text mt-2">@RatingText</MudText>
修改说明
- 用内部私有字段
_activeValue维护组件的当前选中状态,避免直接依赖不可修改的Value参数。 - 通过
OnInitialized和OnParametersSet同步上层传入的Value到内部状态,保证初始值和参数更新时的一致性。 - 实现
OnSelectedValueChanged方法,在MudRating值变化时,先更新内部状态,再通过ValueChanged回调通知上层更新绑定的Model.RoiRating,确保组件重新渲染时Value参数为新值,不会重置MudRating的选中状态。
内容的提问来源于stack exchange,提问作者David Thielen
相关产品推荐
相关产品推荐

