MudBlazor Autocomplete启用CoerceValue=true处理新值时的焦点重置问题
MudBlazor Autocomplete启用CoerceValue=true处理新值时的焦点重置问题
嘿,我完全懂你现在的困境——想要做一个既能选已有客户、又能输入新客户名称的MudBlazor Autocomplete,结果调CoerceValue=true的时候,虽然_customer的状态是对的(要么选中客户要么是null),但组件一重新获得焦点,输入的内容就被重置了;改成false吧,焦点不重置了,但用户改文本后_customer又不会自动变成null,两头为难!
问题根源
先给你捋清楚为啥会这样:当CoerceValue=true时,MudBlazor的Autocomplete有个默认行为——组件获得焦点时,会把Text强制同步成当前Value对应的文本(通过你设置的ToStringFunc生成)。你输入新客户名称时,_customer是null,ToStringFunc返回空字符串,所以焦点一回来,输入的内容就被清成空了。而CoerceValue=false时,组件不会自动同步Text和Value,所以输入的内容能保留,但_customer也不会在用户输入新内容时自动设为null,状态就乱了。
解决方案一:保留CoerceValue=true,手动维护输入状态
这个方案既保留CoerceValue=true对_customer的状态管控,又通过额外变量和事件处理避免焦点重置:
@using System.Threading <MudAutocomplete T="CustomerModel?" Value="@_customer" ValueChanged="CustomerChanged" CoerceValue="true" SearchFunc="SearchFunc" ToStringFunc="@(item => item != null ? item.Name : _userInputText)" Text="@_userInputText" CoerceText="false" TextChanged="OnTextChanged" FocusedChanged="OnFocusedChanged"> <ItemTemplate> @context.Name </ItemTemplate> </MudAutocomplete> @code { private CustomerModel? _customer; // 用这个变量持久化用户输入的文本,不受Value状态影响 private string _userInputText = string.Empty; private Task<IEnumerable<CustomerModel?>> SearchFunc(string value, CancellationToken token) { // 模拟你的现有客户搜索逻辑 var customers = new List<CustomerModel> { new() { Id = 1, Name = "Alice" }, new() { Id = 2, Name = "Bob" }, new() { Id = 3, Name = "Charlie" } }; var filtered = string.IsNullOrEmpty(value) ? customers : customers.Where(c => c.Name.Contains(value, StringComparison.OrdinalIgnoreCase)); return Task.FromResult<IEnumerable<CustomerModel?>>(filtered); } private void CustomerChanged(CustomerModel? customer) { _customer = customer; // 选中客户时,同步输入文本为客户名称 if (customer != null) { _userInputText = customer.Name; } } private void OnTextChanged(string text) { _userInputText = text; // 检查输入是否匹配现有客户,不匹配就把_customer设为null var matchedCustomer = SearchFunc(text, CancellationToken.None).Result.FirstOrDefault(c => c?.Name == text); if (matchedCustomer == null) { _customer = null; } } private void OnFocusedChanged(bool isFocused) { if (isFocused) { // 获得焦点时强制刷新组件,确保显示的是用户输入的文本 StateHasChanged(); } } public class CustomerModel { public int Id { get; set; } public string Name { get; set; } = string.Empty; } }
方案逻辑说明:
- 用
_userInputText专门存用户输入的内容,不管_customer是啥状态,都能保留输入。 - 改写
ToStringFunc:当_customer是null时,返回用户输入的文本,避免CoerceValue把Text清成空。 OnTextChanged里实时检查输入是否匹配现有客户,确保_customer要么是选中的客户,要么是null。OnFocusedChanged触发组件刷新,强制显示用户输入的文本,覆盖CoerceValue的默认重置行为。
解决方案二:关闭CoerceValue,手动同步状态
如果不想依赖CoerceValue的自动同步,也可以把它设为false,然后手动管控_customer和Text的状态:
@using System.Threading <MudAutocomplete T="CustomerModel?" Value="@_customer" ValueChanged="CustomerChanged" CoerceValue="false" SearchFunc="SearchFunc" ToStringFunc="@(item => item?.Name ?? string.Empty)" Text="@_text" CoerceText="false" TextChanged="OnTextChanged"> <ItemTemplate> @context.Name </ItemTemplate> </MudAutocomplete> @code { private CustomerModel? _customer; private string _text = string.Empty; private Task<IEnumerable<CustomerModel?>> SearchFunc(string value, CancellationToken token) { var customers = new List<CustomerModel> { new() { Id = 1, Name = "Alice" }, new() { Id = 2, Name = "Bob" }, new() { Id = 3, Name = "Charlie" } }; var filtered = string.IsNullOrEmpty(value) ? customers : customers.Where(c => c.Name.Contains(value, StringComparison.OrdinalIgnoreCase)); return Task.FromResult<IEnumerable<CustomerModel?>>(filtered); } private void CustomerChanged(CustomerModel? customer) { _customer = customer; // 选中客户时,手动把Text同步为客户名称 if (customer != null) { _text = customer.Name; } } private void OnTextChanged(string text) { _text = text; // 检查输入是否匹配现有客户,不匹配就把_customer设为null var matchedCustomer = SearchFunc(text, CancellationToken.None).Result.FirstOrDefault(c => c?.Name == text); _customer = matchedCustomer; } public class CustomerModel { public int Id { get; set; } public string Name { get; set; } = string.Empty; } }
方案逻辑说明:
CoerceValue=false关闭组件自动同步Text和Value的行为,用户输入的内容不会被焦点重置。- 选中客户时,在
CustomerChanged里手动把Text改成客户名称,保证选中状态的文本正确。 OnTextChanged里实时检查输入是否匹配现有客户,直接把_customer设为匹配的客户或null,确保状态准确。
总结
两种方案都能解决你的问题:第一种适合想保留CoerceValue自动状态管控的场景,第二种更偏向完全手动控制,你可以根据自己的代码习惯选一个用就行~
备注:内容来源于stack exchange,提问作者Vincent
相关产品推荐
相关产品推荐

