- UI组件
- 前端
【免费下载链接】ant-design-blazor
🌈A rich set of enterprise-class UI components based on Ant Design and Blazor.
导读
在 ant-design-blazor 的 Radio 组件体系中,除了手写<Radio>子项和Options数组两种方式外,还提供了一条"零配置"路径:EnumRadioGroup<TEnum>。你只需要定义一个 C# 枚举类型,组件就会在构造时自动遍历枚举成员并生成对应的一组单选框,配合System.ComponentModel.DataAnnotations.Display特性还能自定义每个选项的显示文案。本文以仓库 demo enum-group.md 为骨架,结合 EnumRadioGroup.cs、EnumHelper.cs 与 RadioGroup.razor.cs 的源码,完整讲解它的用法、原理、参数与项目实战场景。
一、枚举方式的核心用法
原 demo 文档的核心表述只有一句:"通过指定枚举类型,来渲染单选框"(Render radios by specific enum type)。在 ant-design-blazor 中,这一能力由泛型组件EnumRadioGroup<TEnum>提供,完整示例见 EnumGroup.razor:
@using System.ComponentModel.DataAnnotations <EnumRadioGroup TEnum="Fruits" @bind-Value="_radioValue" Disabled="_disabled" Name="group1"></EnumRadioGroup> <br /> <EnumRadioGroup TEnum="Fruits" @bind-Value="_radioValue" Disabled="_disabled" ButtonStyle="RadioButtonStyle.Solid" Name="group2"></EnumRadioGroup> <br /> Value: @_radioValue <div style="margin-top: 20px"> <Button Type="ButtonType.Primary" OnClick="_=>_disabled=!_disabled">Toggle Disabled</Button> </div> @code { Fruits _radioValue = Fruits.Apple; bool _disabled; enum Fruits { [Display(Name = "🍎 Apple")] Apple, Pear, Orange } }使用要点可拆解为四步:
- 定义枚举类型:示例中的
Fruits枚举包含Apple、Pear、Orange三个成员,其中Apple通过[Display(Name = "🍎 Apple")]指定了自定义显示文本; - 声明组件并指定泛型参数:
TEnum="Fruits"告诉组件要渲染哪个枚举; - 绑定当前选中值:
@bind-Value="_radioValue"与Fruits _radioValue = Fruits.Apple;双向绑定,初始默认选中Apple; - 按需传入其余参数:
Disabled控制整组禁用、Name设置所有原生input[type="radio"]的 name 属性、ButtonStyle切换按钮风格。
demo 还搭配了一个Toggle Disabled按钮,通过_=>_disabled=!_disabled切换整组禁用状态,方便直观观察禁用效果。
二、为什么枚举方式能"自动渲染":源码实现原理
2.1 EnumRadioGroup :构造函数即渲染
EnumRadioGroup<TEnum>的完整实现非常精简,全部逻辑集中在构造函数中:
public class EnumRadioGroup<TEnum> : RadioGroup<TEnum> { public EnumRadioGroup() { Options = EnumHelper<TEnum>.GetValueLabelList() .Select(x => new RadioOption<TEnum> { Value = x.Value, Label = x.Label }) .ToArray(); } }从源码结构可以梳理出它的工作流程:
- 组件继承自
RadioGroup<TEnum>(见 EnumRadioGroup.cs),因此天然具备RadioGroup的全部能力与参数; - 构造函数调用
EnumHelper<TEnum>.GetValueLabelList(),一次性取出枚举的"值 + 显示名"列表; - 将列表映射为
RadioOption<TEnum>数组并赋给Options属性; RadioGroup的渲染模板检测到Options非空后,不再渲染ChildContent子内容,而是遍历Options逐个生成<Radio>,见 RadioGroup.razor 中Options.IsT1分支:
@foreach (var radio in Options.AsT1) { <Radio Value="radio.Value" RadioButton="IsButton">@radio.Label</Radio> }也就是说,"渲染单选框"这件事完全由枚举到Options的自动转换完成,用户无需再手写任何<Radio>子项。
2.2 EnumHelper :枚举元数据的提取引擎
选项列表的生成依赖EnumHelper<TEnum>(见 EnumHelper.cs)。它的静态构造函数会完成一次性初始化:
static EnumHelper() { _enumType = THelper.GetUnderlyingType<T>(); _aggregateFunction = BuildAggregateFunction(); _valueList = Enum.GetValues(_enumType).Cast<T>(); _valueLabelList = _valueList.Select(value => (value, EnumHelper.GetDisplayName(_enumType, value))); _isFlags = _enumType.GetCustomAttribute<FlagsAttribute>() != null; _hasFlagFunction = BuildHasFlagFunction(); }EnumRadioGroup用到的关键方法是GetValueLabelList(),它返回IEnumerable<(T Value, string Label)>元组集合,Label 的生成规则在内部类EnumHelper.GetDisplayName中定义:
public static string GetDisplayName(Type enumType, object enumValue) { var enumName = Enum.GetName(enumType, enumValue); var fieldInfo = enumType.GetField(enumName); return fieldInfo.GetCustomAttribute<DisplayAttribute>(true)?.GetName() ?? enumName; }由此可以明确两点行为:
- 优先取
[Display(Name = "...")]:枚举成员标注了System.ComponentModel.DataAnnotations.Display特性时,单选框标签使用特性的Name值(示例中即 "🍎 Apple"); - 缺省回退到成员名:未标注特性的成员(如示例的
Pear、Orange)直接使用枚举成员名作为标签。
顺带说明,EnumHelper<TEnum>还提供GetValueList()、Combine()、Split()、IsFlags等能力,前者用于纯值列表,后两者面向[Flags]枚举的按位合并与拆分,是组件库在表单、级联等场景中复用的通用工具。
2.3 RadioGroup 的选项渲染管道
Options参数的类型是OneOf<string[], RadioOption<TValue>[]>(见 RadioGroup.razor.cs),支持两种形态:
| 形态 | 说明 | 渲染方式 |
|---|---|---|
string[] | 纯字符串数组 | 每个字符串既作为Value又作为标签,如Options="@new string[]{"Apple","Pear"}" |
RadioOption<TValue>[] | 值 + 标签(+ 可选 Disabled)结构 | 用radio.Value作为值、radio.Label作为显示文本 |
RadioOption<TValue>的定义见 RadioOption.cs,包含Label、Value、Disabled三个属性。EnumRadioGroup选择的是第二种形态,把枚举值包装成RadioOption<TEnum>数组。
当Options与ChildContent同时存在时,渲染模板优先走Options分支,因此EnumRadioGroup内部无需关心子内容渲染。
三、关键参数与行为详解
由于EnumRadioGroup<TEnum>直接继承RadioGroup<TValue>,以下参数全部可用,参数声明均可在 RadioGroup.razor.cs 中查到:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
TEnum | 泛型参数 | - | 指定要渲染的枚举类型,必须有值 |
Value/@bind-Value | TEnum | - | 当前选中值,双向绑定;DefaultValue可单独指定初始值 |
DefaultValue | TEnum | - | 默认选中值,设置后会同步到CurrentValue |
Disabled | bool | false | 禁用整组单选框,会联动所有子Radio的禁用状态 |
ButtonStyle | RadioButtonStyle? | Outline | 按钮风格,Outline(描边)或Solid(填色),枚举定义见 ButtonStyle.cs |
Name | string | 自动生成 | 组内所有input[type="radio"]的 name 属性;为空时自动用ComponentIdGenerator生成 |
Size | InputSize | Default | 大小,仅对按钮样式生效 |
OnChange | EventCallback<TEnum> | - | 选中值变化后的回调,仅在值真正变化时触发 |
两个值得展开的源码行为:
- Disabled 的联动机制:
RadioGroup.OnInitialized中调用AddRadio注册每个子单选框(见 RadioGroup.razor.cs),若当前Disabled为 true,会通过radio.SetDisabledValue(_disabled)与OnDisabledValueChanged事件同步给所有子项;若某个子项自身已禁用,则不会被组级状态覆盖。 - Name 的自动生成:当
Name未显式指定时,OnInitialized会回退到NameAttributeValue ?? PropertyName ?? ComponentIdGenerator.Generate(this),确保同组单选互斥的 name 语义始终成立。
OnChange的触发逻辑也值得注意(见 RadioGroup.razor.cs):内部先比较新旧值,仅在EqualsValue(oldValue, CurrentValue)为 false 时才InvokeAsync,避免重复回调。
四、从"值列表"到"自定义标签":与 Options 方式的对照
EnumRadioGroup本质上是"枚举 → Options"的语法糖。如果你不想引入枚举,可以手动构造等价的RadioOption<TEnum>[],参考同目录下的 Optional.razor:
RadioOption<string>[] options2 = new RadioOption<string>[] { new(){ Value = "Apple", Label="🍎 Apple", }, new(){ Value = "Pear", Label="🍐 Pear", }, new(){ Value = "Orange", Label="🍊 Orange", }, }; <RadioGroup Options="@options2" @bind-Value="_radioValue" ButtonStyle="RadioButtonStyle.Outline"></RadioGroup>两种方式的差异可以总结为:
| 维度 | EnumRadioGroup<TEnum> | RadioGroup+Options |
|---|---|---|
| 选项来源 | 枚举类型自动提取 | 手动构造数组 |
| 标签自定义 | 通过[Display(Name)]特性 | 通过RadioOption.Label |
| 值类型约束 | 必须是枚举类型TEnum | 任意TValue(string、int、bool 等均可) |
| 适用场景 | 选项与业务枚举一一对应、且需要类型安全 | 选项动态变化、来源为数据或配置 |
因此,当你的选项集合天然对应一个枚举(如状态、类型、方向、对齐方式),优先使用EnumRadioGroup,既能省去手写RadioOption数组的样板代码,又能获得编译期类型安全的@bind-Value绑定;而选项来自数据库、接口等动态数据时,则应使用Options或ChildContent方式。
五、项目实战案例:用枚举单选框控制 Table 列对齐
EnumRadioGroup不仅在 Radio 组件 demo 中出现,也被组件库自身的文档站点复用。在 Table 组件的 ColumnAlignment.razor 示例中,列对齐方式的选择就是通过枚举单选框实现的:
<p>Column alignment: @columnAlign</p> <EnumRadioGroup TEnum="ColumnAlign" @bind-Value="@columnAlign" /> @code{ ColumnAlign columnAlign = ColumnAlign.Left; ... }随后这个columnAlign变量被直接传给多个PropertyColumn的Align属性,实现"切换对齐方式 → 表格列实时重排"的联动效果。这个案例说明了两点:
EnumRadioGroup适合作为设置面板 / 工具栏中的枚举型选项选择器,绑定一个字段即可完成 UI 与状态的同步;- 由于
@bind-Value的泛型类型就是枚举本身,值可以直接参与业务逻辑判断,无需再做字符串转换。
六、小结
EnumRadioGroup<TEnum>是 ant-design-blazor 中"声明式 UI"思想的典型体现:通过EnumHelper<TEnum>在构造函数期将枚举元数据(值 +Display标签)转换为RadioOption<TEnum>[],再复用RadioGroup<TValue>完整的Options渲染管道与参数体系(Disabled、ButtonStyle、Name、Size、OnChange、双向绑定等),让"定义一个枚举、渲染一组单选框"成为一行代码即可完成的操作。
如需进一步探索,可以依次阅读:
- 组件 demo:EnumGroup.razor 与 enum-group.md;
- 组件实现:EnumRadioGroup.cs、RadioGroup.razor.cs、RadioGroup.razor、RadioOption.cs;
- 枚举工具:EnumHelper.cs;
- 同类组件对比:
EnumSelect(EnumSelect.cs)、EnumCheckboxGroup(EnumCheckboxGroup.cs)在 Select、Checkbox 场景下提供了同样的枚举驱动能力。
- UI组件
- 前端
【免费下载链接】ant-design-blazor
🌈A rich set of enterprise-class UI components based on Ant Design and Blazor.
相关推荐
ant-design-blazor 使用枚举类型渲染 Checkbox 组(EnumCheckboxGroup)实战指南
ant design blazor 使用枚举类型渲染 Checkbox 组(EnumCheckboxGroup)实战指南 导读 本文围绕 ant design
UI组件前端Ant Design Blazor 中基于枚举类型渲染 Checkbox 组的完整实战指南
Ant Design Blazor 中基于枚举类型渲染 Checkbox 组的完整实战指南 导读 在 Ant Design Blazor 组件库中, EnumC
前端UI组件设计系统ant-design-blazor 单选框泛型用法完全指南:RadioGroup 的 int、string、bool、bool? 值绑定与枚举扩展
ant design blazor 单选框泛型用法完全指南:RadioGroup 的 int、string、bool、bool? 值绑定与枚举扩展 导读 在 a
前端UI组件设计系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考