MudBlazor子组件中MudDatePicker首次点击无法选中日期问题
问题描述
我将MudDatePicker封装在可复用的Payment组件中,相关代码如下:
父页面代码(Razor)
<MudText>@((MarkupString)paymentsMade)</MudText> <div> <span>Add Payment</span> <MudIconButton Icon="fas fa-solid fa-plus" aria-label="Add Payment" Color="Color.Success" Size="Size.Small" Variant="Variant.Outlined" OnClick="AddPayment"> </MudIconButton> </div> @if (_newClaimModelStep1.PaymentsList.Any()) { foreach (var payment in _newClaimModelStep1.PaymentsList) { <Payment PaymentModel="@payment"></Payment> <MudIconButton Icon="fas fa-solid fa-minus" aria-label="Delete Address" Color="Color.Error" Size="Size.Small" Variant="Variant.Outlined" OnClick="@(() => RemovePayment(payment))"> </MudIconButton> } }
父页面后台代码(C#)
public void AddPayment() { _newClaimModelStep1.PaymentsList.Add(new PaymentInfo()); } protected void RemovePayment(PaymentInfo payment) { _newClaimModelStep1.PaymentsList.Remove(payment); }
Payment组件标记代码(Razor)
<MudItem xs="12" Class="pb-3"> <MudDatePicker @bind-Date="@PaymentModel.PaymentDate" Clearable Editable="true" DateFormat="MM/dd/yyyy" IsDateDisabledFunc="@((DateTime dt) => dt > DateTime.Now.Date)" Mask="@(new DateMask("MM/dd/yyyy"))" Label="Payment Date" Variant="Variant.Outlined" Margin="MudBlazor.Margin.Dense" For="@(() => PaymentModel.PaymentDate)" /> </MudItem>
Payment组件后台代码(C#)
[Parameter] public PaymentInfo PaymentModel { get; set; } = new();
Payment模型(C#)
[Required(ErrorMessageResourceType = typeof(WebResource), ErrorMessageResourceName = nameof(WebResource.PaymentDateRequired))] [DataType(DataType.DateTime)] public DateTime? PaymentDate { get; set; } // MudBlazor needs this to be Nullable
当前异常表现
点击MudDatePicker的日历图标时,首次选择日期无法同步到输入框;需先点击任意其他日期(此时该日期能正常显示),再点击目标日期才生效。直接手动输入日期则完全正常。非嵌入组件或直接将MudDatePicker放在父页面时,无此问题。
可能的原因及修复方案
1. 缺少子组件参数变更通知
Blazor默认不会自动监听引用类型参数内部属性的变化,当PaymentModel.PaymentDate修改时,子组件无法感知到变化并触发重新渲染,导致首次选择日期后UI未同步。
修复方式:
在Payment组件中使用内部变量中转日期绑定,并手动触发状态变更:
[Parameter, EditorRequired] public PaymentInfo PaymentModel { get; set; } = new(); private DateTime? _internalDate; protected override void OnParametersSet() { base.OnParametersSet(); _internalDate = PaymentModel.PaymentDate; } private void OnDateChanged(DateTime? date) { _internalDate = date; PaymentModel.PaymentDate = date; StateHasChanged(); }
同时修改组件内的MudDatePicker绑定:
<MudDatePicker @bind-Date="_internalDate" DateChanged="OnDateChanged" Clearable Editable="true" DateFormat="MM/dd/yyyy" IsDateDisabledFunc="@((DateTime dt) => dt > DateTime.Now.Date)" Mask="@(new DateMask("MM/dd/yyyy"))" Label="Payment Date" Variant="Variant.Outlined" Margin="MudBlazor.Margin.Dense" For="@(() => PaymentModel.PaymentDate)" />
2. Foreach循环未指定唯一Key
父页面使用foreach渲染Payment组件时,未给子组件指定@key,Blazor的Diff算法无法准确识别每个组件的身份,可能导致渲染逻辑异常。
修复方式:
在foreach循环中添加@key,确保每个Payment组件有唯一标识:
@foreach (var payment in _newClaimModelStep1.PaymentsList) { <Payment PaymentModel="@payment" @key="@payment"></Payment> <!-- 移除按钮代码 --> }
如果PaymentInfo没有天然的唯一属性,可给模型添加一个Id字段:
public class PaymentInfo { public Guid Id { get; set; } = Guid.NewGuid(); // 其他原有属性... }
然后将@key绑定到该Id:@key="@payment.Id"
3. 双向绑定的引用类型特性问题
直接绑定到PaymentModel.PaymentDate时,由于PaymentInfo是引用类型,Blazor的变更检测机制可能无法及时捕捉到内部属性的修改,使用内部变量中转可以规避这个问题(即方案1的处理方式)。
内容的提问来源于stack exchange,提问作者JimboJones
相关产品推荐
相关产品推荐

