From d1bfaa2263bc70391b678e881601223c2ac65181 Mon Sep 17 00:00:00 2001 From: maliming Date: Sun, 23 Nov 2025 18:18:08 +0800 Subject: [PATCH] Add support for nullable enums in various components and tag helpers --- .../TagHelpers/Form/AbpSelectTagHelper.cs | 5 ++- .../Form/AbpSelectTagHelperService.cs | 16 +++++--- ...UiObjectExtensionPropertyInfoExtensions.cs | 10 +++++ ...UiObjectExtensionPropertyInfoExtensions.cs | 5 +++ .../ObjectExtending/ExtensionProperties.razor | 2 +- .../SelectExtensionProperty.razor.cs | 40 ++++++++++++++----- .../Pages/Account/AccountManage.razor | 2 +- .../PersonalInfo/Default.cshtml | 5 ++- .../Pages/CmsKit/BlogPosts/Create.cshtml | 5 ++- .../Pages/CmsKit/BlogPosts/Update.cshtml | 5 ++- .../Pages/CmsKit/Blogs/CreateModal.cshtml | 5 ++- .../Pages/CmsKit/Blogs/UpdateModal.cshtml | 5 ++- .../CmsKit/Menus/MenuItems/CreateModal.cshtml | 5 ++- .../CmsKit/Menus/MenuItems/UpdateModal.cshtml | 5 ++- .../Pages/CmsKit/Pages/Create.cshtml | 5 ++- .../Pages/CmsKit/Pages/Update.cshtml | 5 ++- .../Pages/CmsKit/Tags/CreateModal.cshtml | 5 ++- .../Pages/CmsKit/Tags/EditModal.cshtml | 5 ++- .../Pages/Identity/Roles/CreateModal.cshtml | 5 ++- .../Pages/Identity/Roles/EditModal.cshtml | 5 ++- .../Pages/Identity/Users/CreateModal.cshtml | 5 ++- .../Pages/Identity/Users/EditModal.cshtml | 5 ++- .../Tenants/CreateModal.cshtml | 5 ++- .../TenantManagement/Tenants/EditModal.cshtml | 5 ++- 24 files changed, 112 insertions(+), 53 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs index dbcf84437f..d129007d50 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; @@ -14,6 +15,8 @@ public class AbpSelectTagHelper : AbpTagHelper? AspItems { get; set; } public AbpFormControlSize Size { get; set; } = AbpFormControlSize.Default; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs index 248a217495..eab2944002 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs @@ -12,6 +12,7 @@ using Microsoft.Extensions.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions; using Volo.Abp.Localization; +using Volo.Abp.Reflection; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; @@ -169,7 +170,9 @@ public class AbpSelectTagHelperService : AbpTagHelperService private bool IsEnum() { var value = TagHelper.AspFor.Model; - return (value != null && value.GetType().IsEnum) || TagHelper.AspFor.ModelExplorer.Metadata.IsEnum; + return (value != null && value.GetType().IsEnum) || + TagHelper.AspFor.ModelExplorer.Metadata.IsEnum || + (TagHelper.EnumType != null && TypeHelper.IsNullableEnum(TagHelper.EnumType)); } protected virtual async Task GetLabelAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput selectTag) @@ -258,19 +261,20 @@ public class AbpSelectTagHelperService : AbpTagHelperService protected virtual List GetSelectItemsFromEnum(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer) { + var enumType = TagHelper.EnumType ?? explorer.ModelType; + var selectItems = new List(); - var isNullableType = Nullable.GetUnderlyingType(explorer.ModelType) != null; - var enumType = explorer.ModelType; + var isNullableType = Nullable.GetUnderlyingType(enumType!) != null; if (isNullableType) { - enumType = Nullable.GetUnderlyingType(explorer.ModelType)!; + enumType = Nullable.GetUnderlyingType(enumType!)!; selectItems.Add(new SelectListItem()); } var containerLocalizer = _tagHelperLocalizer.GetLocalizerOrNull(explorer.Container.ModelType.Assembly); - foreach (var enumValue in enumType.GetEnumValuesAsUnderlyingType()) + foreach (var enumValue in enumType!.GetEnumValuesAsUnderlyingType()) { var localizedMemberName = _abpEnumLocalizer.GetString(enumType, enumValue, new[] @@ -306,7 +310,7 @@ public class AbpSelectTagHelperService : AbpTagHelperService }; var innerOutput = await labelTagHelper.ProcessAndGetOutputAsync(new TagHelperAttributeList { { "class", "form-label" } }, context, "label", TagMode.StartTagAndEndTag); - + innerOutput.Content.AppendHtml(GetRequiredSymbol(context, output)); return innerOutput.Render(_encoder); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs index d4d1b796ee..62b86bc1c5 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs @@ -88,6 +88,16 @@ public static class MvcUiObjectExtensionPropertyInfoExtensions ?? "text"; //default } + public static bool IsEnum(this ObjectExtensionPropertyInfo propertyInfo) + { + return propertyInfo.Type.IsEnum || TypeHelper.IsNullableEnum(propertyInfo.Type); + } + + public static bool IsNullableEnum(this ObjectExtensionPropertyInfo propertyInfo) + { + return TypeHelper.IsNullableEnum(propertyInfo.Type); + } + private static string? GetInputTypeFromAttributeOrNull(Attribute attribute) { if (attribute is EmailAddressAttribute) diff --git a/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs index fa4994e2f9..3026682f62 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs @@ -218,6 +218,11 @@ public static class BlazoriseUiObjectExtensionPropertyInfoExtensions ?? typeof(TextExtensionProperty<,>); //default } + public static bool IsEnum(this ObjectExtensionPropertyInfo propertyInfo) + { + return propertyInfo.Type.IsEnum || TypeHelper.IsNullableEnum(propertyInfo.Type); + } + private static Type? GetInputTypeFromAttributeOrNull(Attribute attribute) { var hasTextEditSupport = TextEditSupportedAttributeTypes.Any(t => t == attribute.GetType()); diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor index f97b8bac0b..b483288b2e 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor @@ -9,7 +9,7 @@ { if (!propertyInfo.Name.EndsWith("_Text")) { - if (propertyInfo.Type.IsEnum) + if (propertyInfo.IsEnum()) { } diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs index 0dedaf3486..dec24710ec 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Localization; +using System; +using Microsoft.Extensions.Localization; using System.Collections.Generic; using Volo.Abp.Data; @@ -7,23 +8,35 @@ namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending; public partial class SelectExtensionProperty where TEntity : IHasExtraProperties { - protected List> SelectItems = new(); + protected List> SelectItems = new(); - public int SelectedValue { - get { return Entity.GetProperty(PropertyInfo.Name); } + public int? SelectedValue { + get + { + return Entity.GetProperty(PropertyInfo.Name, Nullable.GetUnderlyingType(PropertyInfo.Type!) != null ? null : 0); + } set { Entity.SetProperty(PropertyInfo.Name, value, false); } } - protected virtual List> GetSelectItemsFromEnum() + protected virtual List> GetSelectItemsFromEnum() { - var selectItems = new List>(); + var selectItems = new List>(); + + var isNullableType = Nullable.GetUnderlyingType(PropertyInfo.Type!) != null; + var enumType = isNullableType + ? Nullable.GetUnderlyingType(PropertyInfo.Type)! + : PropertyInfo.Type; - foreach (var enumValue in PropertyInfo.Type.GetEnumValues()) + if (isNullableType) { - selectItems.Add(new SelectItem + selectItems.Add(new SelectItem()); + } + foreach (var enumValue in enumType.GetEnumValues()) + { + selectItems.Add(new SelectItem { Value = (int)enumValue, - Text = AbpEnumLocalizer.GetString(PropertyInfo.Type, enumValue, new []{ StringLocalizerFactory.CreateDefaultOrNull() }) + Text = AbpEnumLocalizer.GetString(enumType, enumValue, new []{ StringLocalizerFactory.CreateDefaultOrNull() }) }); } @@ -37,7 +50,14 @@ public partial class SelectExtensionProperty if (!Entity.HasProperty(PropertyInfo.Name)) { - SelectedValue = (int)PropertyInfo.Type.GetEnumValues().GetValue(0)!; + var isNullableType = Nullable.GetUnderlyingType(PropertyInfo.Type!) != null; + if (!isNullableType) + { + var enumType = isNullableType + ? Nullable.GetUnderlyingType(PropertyInfo.Type)! + : PropertyInfo.Type; + SelectedValue = (int)enumType.GetEnumValues().GetValue(0)!; + } } } } diff --git a/modules/account/src/Volo.Abp.Account.Blazor/Pages/Account/AccountManage.razor b/modules/account/src/Volo.Abp.Account.Blazor/Pages/Account/AccountManage.razor index ea42414679..47ffa4cc48 100644 --- a/modules/account/src/Volo.Abp.Account.Blazor/Pages/Account/AccountManage.razor +++ b/modules/account/src/Volo.Abp.Account.Blazor/Pages/Account/AccountManage.razor @@ -78,7 +78,7 @@ if (!propertyInfo.Name.EndsWith("_Text")) { - if (propertyInfo.Type.IsEnum) + if (propertyInfo.IsEnum()) { } diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.cshtml b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.cshtml index 025aa11142..aab9048d96 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.cshtml +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.cshtml @@ -60,13 +60,14 @@ if (!propertyInfo.Name.EndsWith("_Text")) { - if (propertyInfo.Type.IsEnum || !propertyInfo.Lookup.Url.IsNullOrEmpty()) + if (propertyInfo.IsEnum() || !propertyInfo.Lookup.Url.IsNullOrEmpty()) { - if (propertyInfo.Type.IsEnum) + if (propertyInfo.IsEnum()) { Model.ExtraProperties.ToEnum(propertyInfo.Name, propertyInfo.Type); }