'Generic Selects on MudBlazor

I'm having an issue upgrading a couple of plain vanilla HTML Selects to MudSelect and MudSelectItems. The vanilla Selects worked through a RenderFragment template in order to make them generic and they work pretty well; however, when upgrading them to their MudBlazor counterparts, the @onchange EvenCallBack event is not triggering and nothing happens when the user select items. I've done lots of research but unfortunately I haven't found any examples of generic MudBlazors selects and their documentation is rather lacking.

I'd appreciate if anyone can give me any hints or point me to resources I can lookup. Thanks!

/****Selects on the Blazor page****/
<div class="col-sm">
            <CbgDropDownTemplate Name="Trusts" Label="Select Trust" 
DefaultMessage="Select a Trust" 
                                 LoadingMessage="Loading Trusts..."
                                 Items="_trusts" TItem="Trust"
                                          OnChangeCallBack="OnTrustIdChanged">
                         <OptionTemplate Context="trust">
                             <MudSelectItem Value="@(trust.Abbr)">@trust.Abbr</MudSelectItem>
                         </OptionTemplate>
                     </CbgDropDownTemplate>
                 </div>
                 <div class="col-sm">
                     <CbgDropDownTemplate Name="GroupNumber" Label="Group Number:" 
                                          DefaultMessage="Select Group Number"
                                          Items="_employers" TItem="EmployerContactFlags"
                                          OnChangeCallBack="OnEmployerIdChanged" LoadingMessage="You need to pick a Trust first...">
                         <OptionTemplate Context="employerContactFlags">
                               <MudSelectItem Value="@employerContactFlags.EmployerNumber">@employerContactFlags.EmployerNumber</MudSelectItem>
                             @* <option value="@employerContactFlags.EmployerNumber">@employerContactFlags.EmployerNumber</option> *@
                         </OptionTemplate>
                     </CbgDropDownTemplate>


/**** The Blazor Selects components*****/
@typeparam TItem
<div class="container">
    <div class="form-group">
        <MudSelect T="string" Placeholder="@DefaultMessage"
                   Label="@DefaultValue" Margin="Margin.Dense" Variant="Variant.Text" 
                   @onchange="ChangeCallBack">
            @if (Items != null)
            {
                @foreach (var item in Items)
                {
                    @OptionTemplate(item)
                }
            }
            else
            {
                <MudSelectItem Value="@(LoadingMessage)">"@(LoadingMessage)"</MudSelectItem>
            }
        </MudSelect>
    </div>
</div>

@code {
[Parameter]public string Name { get; set; }
[Parameter]public string Label { get; set; }
[Parameter]public string DefaultMessage { get; set; }
[Parameter]public string DefaultValue { get; set; }
[Parameter]public bool Disabled { get; set; }
[Parameter]public string LoadingMessage { get; set; } = "Loading...";
[Parameter]public RenderFragment<TItem> OptionTemplate { get; set; }
[Parameter]public IReadOnlyList<TItem> Items { get; set; }
[Parameter]public EventCallback<ChangeEventArgs> OnChangeCallBack { get; set; }

Task ChangeCallBack(ChangeEventArgs e)
{
    return OnChangeCallBack.InvokeAsync(e);
}}

/**These are the the classes used in the selects**/
public class Trust
{
    public int Id { get; set; }
    public string Abbr { get; set; }
    public string Name { get; set; }
    public int RenewalId { get; set; }
        
    // GetHashCode and to string overridden for MudBlazor selects components
    public override int GetHashCode() => Id.GetHashCode();   
    // Implement this for the Pizza to display correctly in MudSelect
    public override string ToString() => Name;
}

public partial class EmployerContactFlags
    {
        public int Trust { get; set; }
        public long EmployerNumber { get; set; }
        public long EmployerContactFlag { get; set; }
        public int ContactStatus { get; set; }
        public override string ToString() => EmployerNumber.ToString();
    }


Solution 1:[1]

As your code is rather complex, here's some simple code that demonstrates how to wire up edit controls when you want to encapsulate them in components used to build more complex forms.

You should be able to apply the methodology to your custom control.

First the component. Note:

  1. The definition of the three parameters that @bind binds to.
  2. The wiring of these into the control in the component - in this case MudSelect
  3. The Render fragment for the options list.
// MySelect.razor
@typeparam TValue
@using System.Linq.Expressions

<MudSelect T=TValue [email protected] ValueChanged=this.ValueChanged ValueExpression=this.ValueExpression Label="Select" HelperText="Choose" >
    @ChildContent
</MudSelect>

@code {
    [Parameter] public TValue? Value { get; set; }

    [Parameter] public EventCallback<TValue> ValueChanged { get; set; }

    [Parameter] public Expression<Func<TValue>>? ValueExpression { get; set; }

    [Parameter] public RenderFragment? ChildContent { get; set; }
}

Now the simple editor. Note:

  1. @bind-Value to the model.
  2. The control starts up with the correct selected value
  3. The model is updated as shoiwn in the displayt value.
@page "/"

<PageTitle>Index</PageTitle>

@using Microsoft.Extensions.Options

<MudText Typo="Typo.h3" GutterBottom="true">Demo/MudText</MudText> 

<EditForm Model=model>
    <MySelect @bind-Value=model.Value>
        <MudSelectItem T="int" Value=1>Spain</MudSelectItem>
        <MudSelectItem T="int" Value=2>Portugal</MudSelectItem>
        <MudSelectItem T="int" Value=3>France</MudSelectItem>
    </MySelect>
</EditForm>


<MudText Class="mt-4">Value = @model.Value</MudText>

@code {
    private MyModel model = new();

    public class MyModel
    {
        public int Value { get; set; } = 3;
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1