diff --git a/src/BootstrapBlazor/Components/EditorForm/EditorForm.razor b/src/BootstrapBlazor/Components/EditorForm/EditorForm.razor index a3a6de869f1..c5aef9d2caf 100644 --- a/src/BootstrapBlazor/Components/EditorForm/EditorForm.razor +++ b/src/BootstrapBlazor/Components/EditorForm/EditorForm.razor @@ -40,12 +40,9 @@ } - @if (!_inited) - { -
- -
- } +
+ +
@code diff --git a/src/BootstrapBlazor/Components/EditorForm/EditorForm.razor.cs b/src/BootstrapBlazor/Components/EditorForm/EditorForm.razor.cs index 0b59bac6ca0..356c7668eec 100644 --- a/src/BootstrapBlazor/Components/EditorForm/EditorForm.razor.cs +++ b/src/BootstrapBlazor/Components/EditorForm/EditorForm.razor.cs @@ -191,7 +191,6 @@ public partial class EditorForm : IShowLabel .GroupBy(i => i.GroupOrder).OrderBy(i => i.Key) .Select(i => new KeyValuePair>(i.First().GroupName!, i.OrderBy(x => x.Order))); - private bool _inited; private List? _itemsCache; private List RenderItems @@ -238,29 +237,6 @@ protected override void OnParametersSet() _itemsCache = null; } - /// - /// - /// - /// - protected override async Task OnAfterRenderAsync(bool firstRender) - { - await base.OnAfterRenderAsync(firstRender); - - if (firstRender) - { - foreach (var item in RenderItems) - { - if (item.Lookup == null && !string.IsNullOrEmpty(item.LookupServiceKey)) - { - var lookupServcie = item.LookupService ?? LookupService; - item.Lookup = await lookupServcie.GetItemsAsync(item.LookupServiceKey, item.LookupServiceData); - } - } - _inited = true; - StateHasChanged(); - } - } - private List GetRenderItems() { var items = new List(); @@ -315,7 +291,7 @@ private RenderFragment AutoGenerateTemplate(IEditorItem item) => builder => else { item.PlaceHolder ??= PlaceHolderText; - builder.CreateComponentByFieldType(this, item, Model, ItemChangedType, IsSearch.Value); + builder.CreateComponentByFieldType(this, item, Model, ItemChangedType, IsSearch.Value, item.GetLookupService(LookupService)); } }; diff --git a/src/BootstrapBlazor/Components/Select/Select.razor.cs b/src/BootstrapBlazor/Components/Select/Select.razor.cs index dc6b1eb871f..88b91588a09 100644 --- a/src/BootstrapBlazor/Components/Select/Select.razor.cs +++ b/src/BootstrapBlazor/Components/Select/Select.razor.cs @@ -284,7 +284,10 @@ private SelectedItem? SelectedRow private List GetRowsByItems() { var items = new List(); - items.AddRange(Items); + if (Items != null) + { + items.AddRange(Items); + } items.AddRange(_children); return items; } @@ -306,11 +309,20 @@ protected override void OnParametersSet() { base.OnParametersSet(); - Items ??= []; PlaceHolder ??= Localizer[nameof(PlaceHolder)]; NoSearchDataText ??= Localizer[nameof(NoSearchDataText)]; DropdownIcon ??= IconTheme.GetIconByKey(ComponentIcons.SelectDropdownIcon); ClearIcon ??= IconTheme.GetIconByKey(ComponentIcons.SelectClearIcon); + } + + /// + /// + /// + protected override async Task OnParametersSetAsync() + { + await base.OnParametersSetAsync(); + + Items ??= await GetItemsAsync(); // 内置对枚举类型的支持 if (!Items.Any() && ValueType.IsEnum()) @@ -338,6 +350,16 @@ protected override async Task OnAfterRenderAsync(bool firstRender) } } + private async Task> GetItemsAsync() + { + IEnumerable? items = null; + if (LookupService != null) + { + items = await LookupService.GetItemsByKeyAsync(LookupServiceKey, LookupServiceData); + } + return items ?? []; + } + /// /// 获得/设置 数据总条目 /// diff --git a/src/BootstrapBlazor/Components/Select/SelectBase.cs b/src/BootstrapBlazor/Components/Select/SelectBase.cs index afe7b453cc3..6282372aa78 100644 --- a/src/BootstrapBlazor/Components/Select/SelectBase.cs +++ b/src/BootstrapBlazor/Components/Select/SelectBase.cs @@ -53,6 +53,24 @@ public abstract class SelectBase : PopoverSelectBase [Parameter] public RenderFragment? GroupItemTemplate { get; set; } + /// + /// 获得/设置 服务实例 + /// + [Parameter] + public ILookupService? LookupService { get; set; } + + /// + /// 获得/设置 服务获取 Lookup 数据集合键值 常用于外键自动转换为名称操作,可以通过 传递自定义数据 + /// + [Parameter] + public string? LookupServiceKey { get; set; } + + /// + /// 获得/设置 服务获取 Lookup 数据集合键值自定义数据,通过 指定键值 + /// + [Parameter] + public object? LookupServiceData { get; set; } + /// /// 获得/设置 IIconTheme 服务实例 /// diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.cs b/src/BootstrapBlazor/Components/Table/Table.razor.cs index 2921c619372..17b7af3f915 100644 --- a/src/BootstrapBlazor/Components/Table/Table.razor.cs +++ b/src/BootstrapBlazor/Components/Table/Table.razor.cs @@ -1141,12 +1141,6 @@ private async Task ProcessFirstRender() Columns.Clear(); Columns.AddRange(cols.OrderFunc()); - // 准备 Lookup 数据 - foreach (var column in Columns) - { - column.Lookup ??= await LookupService.GetItemsAsync(column.LookupServiceKey, column.LookupServiceData); - } - // 查看是否开启列宽序列化 _clientColumnWidths = await ReloadColumnWidthFromBrowserAsync(); ResetColumnWidth(); @@ -1329,7 +1323,7 @@ RenderFragment RenderTemplate() => col.Template == null : col.Template(item); RenderFragment RenderEditTemplate() => col.EditTemplate == null - ? new RenderFragment(builder => builder.CreateComponentByFieldType(this, col, item, changedType, false)) + ? new RenderFragment(builder => builder.CreateComponentByFieldType(this, col, item, changedType, false, col.GetLookupService(LookupService))) : col.EditTemplate(item); } @@ -1371,7 +1365,7 @@ void SetDynamicEditTemplate() parameters.Add(new(nameof(ValidateBase.OnValueChanged), onValueChanged.Invoke(d, col, (model, column, val) => DynamicContext.OnValueChanged(model, column, val)))); col.ComponentParameters = parameters; } - builder.CreateComponentByFieldType(this, col, row, changedType, false); + builder.CreateComponentByFieldType(this, col, row, changedType, false, col.GetLookupService(LookupService)); }; } diff --git a/src/BootstrapBlazor/Extensions/IEditorItemExtensions.cs b/src/BootstrapBlazor/Extensions/IEditorItemExtensions.cs index 29b81570756..2071082215a 100644 --- a/src/BootstrapBlazor/Extensions/IEditorItemExtensions.cs +++ b/src/BootstrapBlazor/Extensions/IEditorItemExtensions.cs @@ -12,6 +12,13 @@ namespace BootstrapBlazor.Components; /// public static class IEditorItemExtensions { + /// + /// 判断当前 IEditorItem 实例是否为 Lookup 类型 + /// + /// + /// + public static bool IsLookup(this IEditorItem item) => item.Lookup != null || item.LookupService != null || !string.IsNullOrEmpty(item.LookupServiceKey); + /// /// 判断当前 IEditorItem 实例是否可以编辑 /// @@ -110,4 +117,12 @@ bool ComplexCanWrite() internal static bool GetIgnore(this IEditorItem col) => col.Ignore ?? false; internal static bool GetReadonly(this IEditorItem col) => col.Readonly ?? false; + + /// + /// 获得 ILookupService 实例 + /// + /// + /// + /// + public static ILookupService GetLookupService(this IEditorItem item, ILookupService service) => item.LookupService ?? service; } diff --git a/src/BootstrapBlazor/Utils/Utility.cs b/src/BootstrapBlazor/Utils/Utility.cs index b00a0c2d07e..69a19036d59 100644 --- a/src/BootstrapBlazor/Utils/Utility.cs +++ b/src/BootstrapBlazor/Utils/Utility.cs @@ -459,7 +459,8 @@ public static void CreateDisplayByFieldType(this RenderTreeBuilder builder, IEdi /// /// /// - public static void CreateComponentByFieldType(this RenderTreeBuilder builder, ComponentBase component, IEditorItem item, object model, ItemChangedType changedType = ItemChangedType.Update, bool isSearch = false) + /// + public static void CreateComponentByFieldType(this RenderTreeBuilder builder, ComponentBase component, IEditorItem item, object model, ItemChangedType changedType = ItemChangedType.Update, bool isSearch = false, ILookupService? lookupService = null) { var fieldType = item.PropertyType; var fieldName = item.GetFieldName(); @@ -468,8 +469,7 @@ public static void CreateComponentByFieldType(this RenderTreeBuilder builder, Co var fieldValue = GenerateValue(model, fieldName); var fieldValueChanged = GenerateValueChanged(component, model, fieldName, fieldType); var valueExpression = GenerateValueExpression(model, fieldName, fieldType); - var lookup = item.Lookup; - var componentType = item.ComponentType ?? GenerateComponentType(fieldType, item.Rows != 0, lookup); + var componentType = item.ComponentType ?? GenerateComponentType(item); builder.OpenComponent(0, componentType); if (componentType.IsSubclassOf(typeof(ValidateBase<>).MakeGenericType(fieldType))) { @@ -513,20 +513,22 @@ public static void CreateComponentByFieldType(this RenderTreeBuilder builder, Co } // Nullable - if (item.ComponentType == typeof(Select) && fieldType == typeof(bool?) && lookup == null && item.Items == null) + if (item.ComponentType == typeof(Select) && fieldType == typeof(bool?) && !item.IsLookup() && item.Items == null) { builder.AddAttribute(100, nameof(Select.Items), GetNullableBoolItems(model, fieldName)); } // Lookup - if (lookup != null && item.Items == null) + if (item.IsLookup() && item.Items == null) { builder.AddAttribute(110, nameof(Select.ShowSearch), item.ShowSearchWhenSelect); - builder.AddAttribute(120, nameof(Select.Items), lookup.Clone()); + builder.AddAttribute(120, nameof(Select.LookupService), lookupService); + builder.AddAttribute(121, nameof(Select.LookupServiceKey), item.LookupServiceKey); + builder.AddAttribute(122, nameof(Select.LookupServiceData), item.LookupServiceData); builder.AddAttribute(130, nameof(Select.StringComparison), item.LookupStringComparison); } - // 增加非枚举类,手动设定 ComponentType 为 Select 并且 Data 有值 自动生成下拉框 + // 增加非枚举类,手动设定 ComponentType 为 Select 并且 Items 有值 自动生成下拉框 if (item.Items != null && item.ComponentType == typeof(Select<>).MakeGenericType(fieldType)) { builder.AddAttribute(140, nameof(Select.Items), item.Items.Clone()); @@ -615,15 +617,13 @@ object ComplexPropertyValueExpression() /// /// 通过指定类型生成组件类型 /// - /// - /// 是否为 TextArea 组件 - /// - /// - private static Type GenerateComponentType(Type fieldType, bool hasRows, IEnumerable? lookup) + /// + private static Type GenerateComponentType(IEditorItem item) { + var fieldType = item.PropertyType; Type? ret = null; var type = (Nullable.GetUnderlyingType(fieldType) ?? fieldType); - if (type.IsEnum || lookup != null) + if (type.IsEnum || item.IsLookup()) { ret = typeof(Select<>).MakeGenericType(fieldType); } @@ -649,7 +649,7 @@ private static Type GenerateComponentType(Type fieldType, bool hasRows, IEnumera } else if (fieldType == typeof(string)) { - ret = hasRows ? typeof(Textarea) : typeof(BootstrapInput<>).MakeGenericType(typeof(string)); + ret = item.Rows > 0 ? typeof(Textarea) : typeof(BootstrapInput<>).MakeGenericType(typeof(string)); } return ret ?? typeof(BootstrapInput<>).MakeGenericType(fieldType); } diff --git a/test/UnitTest/Components/EditorFormTest.cs b/test/UnitTest/Components/EditorFormTest.cs index 120ccbee6eb..b6a07f9cfce 100644 --- a/test/UnitTest/Components/EditorFormTest.cs +++ b/test/UnitTest/Components/EditorFormTest.cs @@ -443,6 +443,9 @@ public async Task LookupServiceKey_Ok() var lookup = await lookupService.GetItemsAsync("FooLookup", ""); Assert.NotNull(lookup); Assert.Equal(lookup.Count(), select.Instance.Items.Count()); + + lookup = await lookupService.GetItemsAsync(null, ""); + Assert.Null(lookup); } [Fact]