Skip to content

Commit 1700fbb

Browse files
authored
feat(IEditorItem): add EditorItem generic type (#7642)
* feat: 增加 EditorItem 类 * feat: 增加 HasParameterAttribute 扩展方法 * feat: 增加 RenderEditTemplate 方法 * refactor: 移除参数标签 * test: 增加单元测试 * test: 增加单元测试
1 parent 6dbff8f commit 1700fbb

5 files changed

Lines changed: 409 additions & 9 deletions

File tree

src/BootstrapBlazor/Extensions/PropertyInfoExtensions.cs

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ namespace BootstrapBlazor.Components;
99

1010
/// <summary>
1111
/// <para lang="zh">PropertyInfo 扩展方法</para>
12-
/// <para lang="en">PropertyInfo 扩展方法</para>
12+
/// <para lang="en">PropertyInfo extension methods</para>
1313
/// </summary>
1414
public static class PropertyInfoExtensions
1515
{
1616
/// <summary>
1717
/// <para lang="zh">判断属性是否为静态属性</para>
18-
/// <para lang="en">判断propertywhether为静态property</para>
18+
/// <para lang="en">Determines whether the property is static</para>
1919
/// </summary>
2020
/// <param name="p"></param>
2121
public static bool IsStatic(this PropertyInfo p)
@@ -25,17 +25,12 @@ public static bool IsStatic(this PropertyInfo p)
2525
}
2626

2727
/// <summary>
28-
/// <para lang="zh">判断属性是否只读扩展方法</para>
29-
/// <para lang="en">判断propertywhether只读扩展方法</para>
28+
/// <para lang="zh">判断属性是否可以写入扩展方法</para>
29+
/// <para lang="en">Determines whether the property can be written to extension method</para>
3030
/// </summary>
3131
/// <param name="p"></param>
3232
public static bool IsCanWrite(this PropertyInfo p) => p.CanWrite && !p.IsInit();
3333

34-
/// <summary>
35-
/// <para lang="zh">判断是否为 Init 扩展方法</para>
36-
/// <para lang="en">判断whether为 Init 扩展方法</para>
37-
/// </summary>
38-
/// <param name="p"></param>
3934
private static bool IsInit(this PropertyInfo p)
4035
{
4136
var isInit = false;
@@ -50,4 +45,30 @@ private static bool IsInit(this PropertyInfo p)
5045
}
5146
return isInit;
5247
}
48+
49+
/// <summary>
50+
/// <para lang="zh">判断属性是否有指定类型的 Parameter 特性</para>
51+
/// <para lang="en">Determines whether the property has a Parameter attribute of the specified type</para>
52+
/// </summary>
53+
/// <param name="modelProperty"></param>
54+
/// <param name="type"></param>
55+
public static bool HasParameterAttribute(this PropertyInfo? modelProperty, Type type)
56+
{
57+
if (modelProperty is null)
58+
{
59+
return false;
60+
}
61+
62+
// 必须带有 Parameter 特性
63+
if (!modelProperty.IsDefined(typeof(ParameterAttribute), inherit: true))
64+
{
65+
return false;
66+
}
67+
68+
// 处理可空类型,并使用可赋值性检查类型兼容性
69+
var propertyType = Nullable.GetUnderlyingType(modelProperty.PropertyType) ?? modelProperty.PropertyType;
70+
var targetType = Nullable.GetUnderlyingType(type) ?? type;
71+
72+
return targetType.IsAssignableFrom(propertyType);
73+
}
5374
}
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the Apache 2.0 License
3+
// See the LICENSE file in the project root for more information.
4+
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
5+
6+
namespace BootstrapBlazor.Components;
7+
8+
/// <summary>
9+
/// <para lang="zh">EditorItem 表单渲染项实体类</para>
10+
/// <para lang="en">EditorItem form field class</para>
11+
/// </summary>
12+
/// <param name="fieldName"></param>
13+
/// <param name="fieldType"></param>
14+
/// <param name="fieldText"></param>
15+
public class EditorItem<TModel>(string fieldName, Type fieldType, string? fieldText = null) : IEditorItem
16+
{
17+
private string FieldName { get; } = fieldName;
18+
19+
/// <summary>
20+
/// <inheritdoc cref="IEditorItem.SkipValidate"/>
21+
/// </summary>
22+
public bool SkipValidate { get; set; }
23+
24+
/// <summary>
25+
/// <inheritdoc cref="IEditorItem.Ignore"/>
26+
/// </summary>
27+
public bool? Ignore { get; set; }
28+
29+
/// <summary>
30+
/// <inheritdoc cref="IEditorItem.Readonly"/>
31+
/// </summary>
32+
public bool? Readonly { get; set; }
33+
34+
/// <summary>
35+
/// <inheritdoc cref="IEditorItem.Required"/>
36+
/// </summary>
37+
public bool? Required { get; set; }
38+
39+
/// <summary>
40+
/// <inheritdoc cref="IEditorItem.RequiredErrorMessage"/>
41+
/// </summary>
42+
public string? RequiredErrorMessage { get; set; }
43+
44+
/// <summary>
45+
/// <inheritdoc cref="IEditorItem.ShowLabelTooltip"/>
46+
/// </summary>
47+
public bool? ShowLabelTooltip { get; set; }
48+
49+
/// <summary>
50+
/// <inheritdoc cref="IEditorItem.PlaceHolder"/>
51+
/// </summary>
52+
public string? PlaceHolder { get; set; }
53+
54+
/// <summary>
55+
/// <inheritdoc cref="IEditorItem.PropertyType"/>
56+
/// </summary>
57+
public Type PropertyType { get; } = fieldType;
58+
59+
[Obsolete("已弃用,请删除;Deprecated, please delete")]
60+
[ExcludeFromCodeCoverage]
61+
bool IEditorItem.Editable { get; set; } = true;
62+
63+
/// <summary>
64+
/// <inheritdoc cref="IEditorItem.Step"/>
65+
/// </summary>
66+
public string? Step { get; set; }
67+
68+
/// <summary>
69+
/// <inheritdoc cref="IEditorItem.Rows"/>
70+
/// </summary>
71+
public int Rows { get; set; }
72+
73+
/// <summary>
74+
/// <inheritdoc cref="IEditorItem.Cols"/>
75+
/// </summary>
76+
public int Cols { get; set; }
77+
78+
/// <summary>
79+
/// <inheritdoc cref="IEditorItem.Text"/>
80+
/// </summary>
81+
[NotNull]
82+
public string? Text { get; set; } = fieldText;
83+
84+
/// <summary>
85+
/// <inheritdoc cref="IEditorItem.EditTemplate"/>
86+
/// </summary>
87+
public RenderFragment<TModel>? EditTemplate { get; set; }
88+
89+
RenderFragment<object>? IEditorItem.EditTemplate
90+
{
91+
get
92+
{
93+
return EditTemplate == null ? null : new RenderFragment<object>(item => builder =>
94+
{
95+
builder.AddContent(0, EditTemplate((TModel)item));
96+
});
97+
}
98+
set
99+
{
100+
}
101+
}
102+
103+
/// <summary>
104+
/// <inheritdoc cref="IEditorItem.ComponentType"/>
105+
/// </summary>
106+
public Type? ComponentType { get; set; }
107+
108+
/// <summary>
109+
/// <inheritdoc cref="IEditorItem.ComponentParameters"/>
110+
/// </summary>
111+
public IEnumerable<KeyValuePair<string, object>>? ComponentParameters { get; set; }
112+
113+
/// <summary>
114+
/// <inheritdoc cref="IEditorItem.Items"/>
115+
/// </summary>
116+
public IEnumerable<SelectedItem>? Items { get; set; }
117+
118+
/// <summary>
119+
/// <inheritdoc cref="IEditorItem.Order"/>
120+
/// </summary>
121+
public int Order { get; set; }
122+
123+
/// <summary>
124+
/// <inheritdoc cref="ILookup.Lookup"/>
125+
/// </summary>
126+
public IEnumerable<SelectedItem>? Lookup { get; set; }
127+
128+
/// <summary>
129+
/// <inheritdoc cref="IEditorItem.ShowSearchWhenSelect"/>
130+
/// </summary>
131+
public bool ShowSearchWhenSelect { get; set; }
132+
133+
[Obsolete("已弃用,请删除;Deprecated, please delete")]
134+
[ExcludeFromCodeCoverage]
135+
bool IEditorItem.IsFixedSearchWhenSelect { get; set; }
136+
137+
/// <summary>
138+
/// <inheritdoc cref="IEditorItem.IsPopover"/>
139+
/// </summary>
140+
public bool IsPopover { get; set; }
141+
142+
/// <summary>
143+
/// <inheritdoc cref="ILookup.LookupStringComparison"/>
144+
/// </summary>
145+
public StringComparison LookupStringComparison { get; set; } = StringComparison.OrdinalIgnoreCase;
146+
147+
/// <summary>
148+
/// <inheritdoc cref="ILookup.LookupServiceKey"/>
149+
/// </summary>
150+
public string? LookupServiceKey { get; set; }
151+
152+
/// <summary>
153+
/// <inheritdoc cref="ILookup.LookupServiceData"/>
154+
/// </summary>
155+
public object? LookupServiceData { get; set; }
156+
157+
/// <summary>
158+
/// <inheritdoc cref="ILookup.LookupService"/>
159+
/// </summary>
160+
public ILookupService? LookupService { get; set; }
161+
162+
/// <summary>
163+
/// <inheritdoc cref="ITableColumn.OnCellRender"/>
164+
/// </summary>
165+
public Action<TableCellArgs>? OnCellRender { get; set; }
166+
167+
/// <summary>
168+
/// <inheritdoc cref="IEditorItem.ValidateRules"/>
169+
/// </summary>
170+
public List<IValidator>? ValidateRules { get; set; }
171+
172+
/// <summary>
173+
/// <inheritdoc cref="IEditorItem.GroupName"/>
174+
/// </summary>
175+
public string? GroupName { get; set; }
176+
177+
/// <summary>
178+
/// <inheritdoc cref="IEditorItem.GroupOrder"/>
179+
/// </summary>
180+
public int GroupOrder { get; set; }
181+
182+
/// <summary>
183+
/// <inheritdoc cref="IEditorItem.GetDisplayName"/>
184+
/// </summary>
185+
public string GetDisplayName() => Text;
186+
187+
/// <summary>
188+
/// <inheritdoc cref="IEditorItem.GetFieldName"/>
189+
/// </summary>
190+
public string GetFieldName() => FieldName;
191+
}

src/BootstrapBlazor/Utils/BootstrapDynamicComponent.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,28 @@ public RenderFragment Render() => builder =>
5353
}
5454
builder.CloseComponent();
5555
};
56+
57+
/// <summary>
58+
/// <para lang="zh">创建组件实例并渲染 Model 参数</para>
59+
/// <para lang="en">Create component instance and render</para>
60+
/// </summary>
61+
public RenderFragment<TModel> RenderEditTemplate<TModel>(string? modelParameterName = null) => model => builder =>
62+
{
63+
var index = 0;
64+
builder.OpenComponent(index++, componentType);
65+
if (parameters != null)
66+
{
67+
modelParameterName ??= "Model";
68+
var modelProperty = componentType.GetPropertyByName(modelParameterName);
69+
if (modelProperty.HasParameterAttribute(typeof(TModel)))
70+
{
71+
builder.AddAttribute(index++, modelParameterName, model);
72+
}
73+
foreach (var p in parameters)
74+
{
75+
builder.AddAttribute(index++, p.Key, p.Value);
76+
}
77+
}
78+
builder.CloseComponent();
79+
};
5680
}

test/UnitTest/Extensions/ObjectExtensionsTest.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,17 @@ public void IsStatic_Ok()
303303
Assert.True(pi.IsStatic());
304304
}
305305

306+
[Fact]
307+
public void HasParameterAttribute_Ok()
308+
{
309+
var instance = new MockObject();
310+
var pi = instance.GetType().GetProperty("Mock");
311+
Assert.False(pi.HasParameterAttribute(typeof(Foo)));
312+
313+
pi = instance.GetType().GetProperty(nameof(instance.Foo));
314+
Assert.False(pi.HasParameterAttribute(typeof(Foo)));
315+
}
316+
306317
[Fact]
307318
public void CreateInstance_Ok()
308319
{

0 commit comments

Comments
 (0)