Blazor에서 Data Validation을 지원하는 InputSelect 컴포넌트는 enum 복수 선택할 때 배열로 처리하기 때문에, flag enum 형식의 속성에 데이터 바인딩을 직접 거는 것이 불가능합니다.
그래서, EditForm에서 간편하게 바인딩할 수 있는 체크박스 컴포넌트를 작성해봤습니다.
// InputFlaggedEnum.razor
@typeparam TEnum
@inject IStringLocalizer<TypeNames> TypeLocalizer
<div class="btn-group" role="group" >
    @foreach (var key in _memberInts.Keys)
    {
        <input type="checkbox" class="btn-check" id="@key.ToString()" autocomplete="off"
            @onchange="@(() => OnCheckChanged(key))" checked="@_checkedStataus[key]" />
        <label class="btn btn-outline-success" for="@key.ToString()">@TypeLocalizer[key.ToString()]</label>
    }
</div>
@code {
    [Parameter]
    [EditorRequired]
    public TEnum? Options { get; set; }
    [Parameter]
    public TEnum? Value { get; set; }
    private int _valueInt;
    [Parameter]
    public EventCallback<TEnum> ValueChanged { get; set; }
    private Dictionary<TEnum, int> _memberInts = new();
    private Dictionary<TEnum, bool> _checkedStataus = new();
    private async void OnCheckChanged(TEnum selected)
    {
        _checkedStataus[selected] = !_checkedStataus[selected];
        var memberInt = _memberInts[selected];
        if (_checkedStataus[selected])
        {
            Value = StringToEnum( (_valueInt |= memberInt).ToString() );
        }
        else
        {
            Value = StringToEnum( (_valueInt &= (_valueInt ^ memberInt)).ToString() );
        }
        await ValueChanged.InvokeAsync(Value);
    }
    protected override void OnInitialized()
    {
        base.OnInitialized();
        if(Options != null)
        {
            var enumType = Options.GetType();
            if (enumType.IsEnum)
            {
                var optionInt = EnumToInt(Options);
                foreach (var member in Enum.GetValues(enumType))
                {
                    if (System.Numerics.BitOperations.PopCount((uint)(int)member) != 1)
                        continue;
                    var memberNum = (int)member;
                    if ((memberNum & optionInt) == memberNum)
                    {
                        _memberInts[(TEnum)member] = memberNum;
                        _checkedStataus[(TEnum)member] = false;
                    }
                }
                if (Value != null)
                {
                    _valueInt = EnumToInt(Value);
                    if (_valueInt != 0)
                    {
                        foreach (var memberInt in _memberInts)
                        {
                            if ((_valueInt & memberInt.Value) == memberInt.Value)
                            {
                                _checkedStataus[memberInt.Key] = true;
                            }
                        }
                    }
                }
            }
        }
    }
    private int EnumToInt(TEnum value)
    {
        return (int)Enum.Parse(typeof(TEnum), value.ToString());
    }
    private TEnum StringToEnum(string numOrConstant)
    {
        return (TEnum)Enum.Parse(typeof(TEnum), numOrConstant);
    }
}
[Flags]
public enum DayOfWeekFlag
{
    Non = 0, // == defualtOf(DayOfWeekFlag)
    Sun = 1 << DayOfWeek.Sunday,
    Mon = 1 << DayOfWeek.Monday,
    Tue = 1 << DayOfWeek.Tuesday,
    Wed = 1 << DayOfWeek.Wednesday,
    Thu = 1 << DayOfWeek.Thursday,
    Fri = 1 << DayOfWeek.Friday,
    Sat = 1 << DayOfWeek.Saturday,
    End = 0b100_0001,
    All = 0b111_1111,
}
사용하기
// index.razor
@attribute [Route(Routes.Index)]
@inject IStringLocalizer<TypeNames> TypeLocalizer
@code {
    private DayOfWeekFlag DayOfWeek { get; set; } = DayOfWeekFlag.End;
}
@{
    var options = DayOfWeekFlag.All;
}
<InputFlaggedEnum Options="@options" @bind-Value="@DayOfWeek"/>
<h3>
     @string.Join("", DayOfWeek
                        .ToString()
                        .Split(", ")
                        .Select( x => TypeLocalizer[x].ToString())
                        .ToArray())
</h3>
초기값

체크 변경
옵션 변경
// index.razor
...
@{
    var options = DayOfWeekFlag.All ^ DayOfWeekFlag.End;
}
...
변경된 초기값




