目录
本系列中的所有BlazorForms文章
- BlazorForms低代码开源框架——第1部分:介绍和种子项目
- BlazorForms低代码开源框架——第2部分:CrmLight项目
- BlazorForms低代码开源框架——第3部分:CrmLight Lead Board
介绍
当您需要为客户构建工作原型或您的公司没有企业开发预算时,您别无选择,需要使用一些捷径和生活技巧,通常是低代码或无代码方法。在这篇文章中,我介绍了一种如何使用开源框架BlazorForms快速开发UI的方法。
快速开发不是这里唯一的优势,您还可以获得低维护和可预测的解决方案,以后可以使用自定义UI进行改进并通过移动版本进行扩展。
BlazorForms需要最少的UI开发知识,并有助于将数据实体呈现为单页应用程序。
为了尽量减少最初的工作量,我们创建了GitHub上提供的种子项目,我将最新的种子项目版本0.7.0复制到我的博客存储库中。
从GitHub下载此博客文章代码:
GitHub上的BlazorForms项目:
种子项目
BlazorForms作为PRO CODERS PTY LTD的内部项目开发了几年——澳大利亚面向质量专家的咨询,现在我们决定将其分享给开源社区。
我们的框架将应用程序与Flow、表单和规则分开。这可以防止面条式编码并减少运行时错误的数量,它还完全支持Visual Studio智能。
为了演示哪个组件的含义及其外观,最好打开种子项目,让我们使用Visual Studio 2022来完成。
BlazorFormsSeed
此项目是使用Visual Studio Blazor Server应用模板创建的,然后我们添加了NuGet包:
- BlazorForms 0.7.0
- BlazorForms.Rendering.MudBlazorUI 0.7.0
它还间接引用了MudBlazor 6.1.5——实现Blazor Material Design的开源框架。
图1
导航菜单和布局也更改为使用MudBlazor。
运行应用程序时,您可以看到动态生成的简单表单,它绑定到模型,支持验证,并且它是Flow中的一个步骤,用于控制在提交或关闭表单时要显示的表单以及要执行的操作。
图2
所有示例代码都位于 Flows\SampleFlow.cs 文件中,为了简单起见,我们将几个类放在一起。
Model
在文件的底部,您可以找到一个Model类,这对于此方法至关重要。Model由将在流和窗体中使用的属性组成,编译器将检查是否在代码中使用了现有属性和正确的类型。
C#
public class MyModel1 : IFlowModel
{
public virtual string? Message { get; set; }
public virtual string? Name { get; set; }
public virtual string? Logs { get; set; }
}
Flow
定义Flow时,我们将Model作为FluentFlowBase<>泛型类型的模板参数引用,因此编译器知道该Model类型,并且可以检查我们是否仅使用现有属性。
public class SampleFlow : FluentFlowBase<MyModel1>
{
public override void Define()
{
this
.Begin()
.NextForm(typeof(QuestionForm))
.If(() => Model.Name?.ToLower() == "admin")
.Next(() => Model.Logs = "Flow = 'SampleFlow'\r\nLast Form = 'QuestionForm'\r\nLast Action = 'Submit'")
.NextForm(typeof(AdminForm))
.Else()
.Next(() => { Model.Message = $"Welcome {Model.Name}"; })
.EndIf()
.NextForm(typeof(WellcomeForm))
.End();
}
}
定义方法指定一系列步骤和条件分支,这些步骤和条件分支共同控制演示flow。
在示例流中,我们定义了:
- 最初显示QuestionForm并且Flow将等待用户输入
- 按下“取消”按钮时,将终止Flow
- 按下“提交”按钮时,Flow将继续执行下一条语句——If
- 在If语句中,Flow检查条件(输入的名称等于“admin”)
- 输入“admin”时,Logs将填充并显示AdminForm属性
- 输入其他内容时,Message将填充并显示该WellcomeForm属性
Form
在Flow中,我们使用了三种不同的Form将UI控件附加到作为模板参数提供给泛型class FormEditBase<>的Model。
public class QuestionForm : FormEditBase<MyModel1>
{
protected override void Define(FormEntityTypeBuilder<MyModel1> f)
{
f.DisplayName = "BlazorForms Sample";
f.Property(p => p.Name).Label("What is your name?").IsRequired();
f.Button("/", ButtonActionTypes.Close, "Cancel");
f.Button("/", ButtonActionTypes.Submit);
}
}
public class AdminForm : FormEditBase<MyModel1>
{
protected override void Define(FormEntityTypeBuilder<MyModel1> f)
{
f.Property(p => p.Logs).Control(ControlType.TextArea).IsReadOnly();
f.Button("/", ButtonActionTypes.Close);
}
}
public class WellcomeForm : FormEditBase<MyModel1>
{
protected override void Define(FormEntityTypeBuilder<MyModel1> f)
{
f.Property(p => p.Message).Control(ControlType.Header);
f.Button("/", ButtonActionTypes.Close);
}
}
在QuestionForm的Define方法中,我们有:
- 渲染Form字幕“BlazorForms Sample”
- 对于Model属性,Name呈现所需的输入控件
- 渲染按钮“取消”,按下后终止Flow
- 提交Form并继续Flow的渲染按钮“提交”
同样,AdminForm呈现一个只读文本区域,该区域显示Logs属性,并且只有一个按钮在按下时终止Flow;并且WellcomeForm呈现显示Message属性和“关闭”按钮的标头控件。
您还记得,Logs和Message属性的值在flow逻辑中填充。
基本上,所有代码逻辑都包含在Flow和规则中,但Form仅定义应在UI中呈现的Model属性和控件之间的绑定。
Rule
规则可以附加到Form上的每个属性,并且当值更改时将触发规则。在Rule中,可以放置可以触发验证错误、隐藏或显示控件、更改Model属性值等的逻辑。
基本的种子项目没有Rule的示例,但我会添加一个小的修改来演示它。
我修改QuestionForm并添加了NotWombatRule。
public class QuestionForm : FormEditBase<MyModel1>
{
protected override void Define(FormEntityTypeBuilder<MyModel1> f)
{
f.DisplayName = "BlazorForms Sample";
f.Property(p => p.Name).Label("What is your name?")
.IsRequired().Rule(typeof(NotWombatRule));
f.Property(p => p.Message).Control(ControlType.Label).Label("").IsHidden();
f.Button("/", ButtonActionTypes.Close, "Cancel");
f.Button("/", ButtonActionTypes.Submit);
}
}
public class NotWombatRule : FlowRuleBase<MyModel1>
{
public override string RuleCode => "SFS-1";
public override void Execute(MyModel1 model)
{
if (model.Name?.ToLower() == "wombat")
{
model.Message = "really?";
Result.Fields[SingleField(m => m.Message)].Visible= true;
}
else
{
model.Message = "";
Result.Fields[SingleField(m => m.Message)].Visible = false;
}
}
}
如您所见,QuestionForm现在有一个隐藏的Message属性控件并NotWombatRule附加到属性Name。当用户输入“wombat”到Name字段并按 Tab 将焦点移动到下一个控件时,Rule将触发,它将检查输入的Name和Message内容并显示:
图3
规则还接受模型模板参数并支持类型安全,如果使用不存在的Model属性或与其类型不匹配,则会看到编译错误。
Blazor Page
定义Flow、Form和规则后,我们可以在Blazor页面上使用它们。项目页面文件夹包含 Sample.razor 文件。
@page "/sample"
<FlowEditForm FlowName="@typeof(BlazorFormsSeed.Flows.SampleFlow).FullName"
Options="Options" NavigationSuccess="/" />
@code {
EditFormOptions Options = new EditFormOptions
{ MudBlazorProvidersDefined = true, Variant=Variant.Filled };
}
我们在此处放置了FlowEditForm razor组件并提供了一些参数:Flow的类型、选项以及流完成后的导航位置。
当用户导航到“/sample”页面时,BlazorForms框架会创建一个SampleFlow实例并开始逐步执行它。当满足第一个Form时,它会呈现Form数据并等待用户输入。输入数据并提交表单后,Flow执行将一直持续到结束。
Program.cs和_Hosts.cshtml
我应该提到的最后一件事是如何在Blazor应用程序中注册BlazorForms框架。它是在program .cs文件中完成的:
// BlazorForms
builder.Services.AddServerSideBlazorForms();
builder.Services.AddBlazorFormsMudBlazorUI();
builder.Services.AddBlazorFormsServerModelAssemblyTypes(typeof(SampleFlow));
var app = builder.Build();
// BlazorForms
app.BlazorFormsRun();
并且应该将CSS和JavaScript文件的引用添加到_Hosts.cshtml文件中:
<!-- MudBlazor -->
<link href="https://fonts.googleapis.com/css?
family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
总结
在这篇文章中,我介绍了BlazorForms框架——一个开源项目,它简化了Blazor UI开发,并允许创建简单且可维护的C#代码,这对于低预算项目和原型设计非常有用。主要思想是将逻辑放置到不依赖于UI且可进行单元测试的流和规则中;窗体仅包含模型和UI控件之间的绑定。
这篇文章是对BlazorForms的简要介绍,我没有介绍不同类型的流,如何在会话之间存储流状态,如何在JSON中定义流和表单,而不是C#和许多其他功能。所有这些都将在稍后的博客中介绍。
PRO CODERS团队认为,BlazorForms框架甚至可以用于大型项目,在这些项目中,应该以最少的努力和可接受的质量实现和维护数百个表单。它应该是自定义UI实现的一个很好的替代方案,其中每个页面/表单都需要巨大的努力来开发和测试,然后当随着时间的推移添加修改时,质量会下降。
下一个——CrmLightDemoApp种子项目
稍后将介绍更复杂的场景,我们将开始研究CrmLightDemoApp种子项目。
它有几个流连接到实现CRUD操作的存储库,现在,我将提供几个屏幕截图:
图4
图5
图6
您可以在我的GitHub文件夹Story-08-BlazorForms-Intro-Seeds上找到完整的解决方案代码:
https://www.codeproject.com/Articles/5351558/BlazorForms-Low-Code-Open-Source-Framework-Part-1