You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 12:59:33