CodeBeamOrg / CodeBeam.MudBlazor.Extensions

Useful third party extension components for MudBlazor, from the contributors.
https://mudextensions.codebeam.org/
MIT License
367 stars 62 forks source link

Can MudSelect extension support enum types? #205

Open neozhu opened 1 year ago

neozhu commented 1 year ago

I was wondering if there are any plans to add support for enum types in MudSelect? I think this feature is quite useful in actual projects, and having a new component that supports enums would save a lot of time. If this is not currently on the roadmap, I would be happy to provide an example of how this feature could be used. Thank you for your time and consideration.

@using MudBlazor
@using System.ComponentModel
@using System.Reflection;
@typeparam TEnum

@inherits MudSelect<TEnum> 
@{
    base.BuildRenderTree(__builder);
}
@code {
    bool _isFlagsEnum;
    private static bool IsNullableEnum => Nullable.GetUnderlyingType(typeof(TEnum))?.IsEnum ?? false;

    private static IList<TEnum> EnumValueList() => EnumOrUnderlyingType().GetEnumValues().Cast<TEnum>().ToList();

    private static Type EnumOrUnderlyingType() => IsNullableEnum ? Nullable.GetUnderlyingType(typeof(TEnum)) : typeof(TEnum);

    protected override void OnInitialized()
    {
        Dense = true;
        TransformOrigin = Origin.TopLeft;
        AnchorOrigin = Origin.BottomLeft;
        _isFlagsEnum = EnumOrUnderlyingType().GetCustomAttribute<FlagsAttribute>() != null;
        MultiSelection = _isFlagsEnum;
        base.OnInitialized();
    }

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        await base.SetParametersAsync(parameters);
        Setup();
        setSelectedValues();
    }
    private void setSelectedValues()
    {
        if (_isFlagsEnum)
        {
            var valueEnum = Value as Enum;
            var toSelect = EnumValueList().Where(e => valueEnum?.HasFlag((e as Enum)!) == true).ToList();
            SelectedValues = toSelect;
        }
        else if (Value != null)
        {
            SelectedValues = new[] { Value };
        }
    }

    void Setup()
    {
        if (ChildContent == null)
        {
            ChildContent = __builder =>
            {
                @foreach (TEnum item in EnumValueList())
                {
                    <MudSelectItem T="TEnum" Value="@item">@(GetDescriptionText(item))</MudSelectItem>
                }
            };
        }
    }

    string GetDescriptionText<T>(T val)
    {
        if (val is null) return string.Empty;
        var attributes = (DescriptionAttribute[])val.GetType().GetField(val!.ToString()!)!.GetCustomAttributes(typeof(DescriptionAttribute), false);
        return attributes.Length > 0 ? attributes[0].Description : val!.ToString()!;
    }
    private T SetFlag<T>(T flag, bool set)
    {
        Enum value = Value as Enum;

        Type underlyingType = Enum.GetUnderlyingType(EnumOrUnderlyingType());

        // note: AsInt mean: math integer vs enum (not the c# int type)
        dynamic valueAsInt = Convert.ChangeType(value, underlyingType);
        dynamic flagAsInt = Convert.ChangeType(flag, underlyingType);
        if (set)
            valueAsInt |= flagAsInt;
        else
            valueAsInt &= ~flagAsInt;

        return (T)valueAsInt;
    }
}
mckaragoz commented 1 year ago

Hi, you can use enums with ItemCollection like:

<MudSelectExtended ItemCollection="@(Enum.GetValues<EnumType>())" \>

Isn't it fulfill your requirements?

neozhu commented 1 year ago

Hi, you can use enums with ItemCollection like:

<MudSelectExtended ItemCollection="@(Enum.GetValues<EnumType>())" \>

Isn't it fulfill your requirements?

Thank you for your response and suggestion. Your solution using enums with ItemCollection can work, but in my case, I need to display the items based on their Description and also support nullable values. However, I will try your approach and see if I can modify it to meet my requirements.

michaelswells commented 10 months ago

Hi, you can use enums with ItemCollection like: <MudSelectExtended ItemCollection="@(Enum.GetValues<EnumType>())" \> Isn't it fulfill your requirements?

Thank you for your response and suggestion. Your solution using enums with ItemCollection can work, but in my case, I need to display the items based on their Description and also support nullable values. However, I will try your approach and see if I can modify it to meet my requirements.

Would you post your solution to use enum's description and nullable values?