65.9K
CodeProject 正在变化。 阅读更多。
Home

BlazorForms 低代码开源框架。第一部分:简介和种子项目

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.71/5 (13投票s)

2023 年 1 月 9 日

CPOL

6分钟阅读

viewsIcon

26353

利用 C# 的类型安全优势,基于流程、表单和规则开发应用程序

本系列中所有 BlazorForms 文章

引言

当您需要为客户构建可用的原型,或者您的公司没有企业开发预算时,您别无选择,只能使用一些捷径和技巧,通常是低代码或无代码方法。在这篇文章中,我将介绍一种使用开源框架 BlazorForms 快速开发 UI 的方法。

快速开发不是这里唯一的优势,您还可以获得低维护和可预测的解决方案,之后可以通过自定义 UI 进行改进,并通过移动版本进行扩展。

BlazorForms 需要最少的 UI 开发知识,并有助于将数据实体呈现为单页应用程序。

为了最大限度地减少初始工作量,我们创建了种子项目,这些项目可在 GitHub 上找到,我已将最新种子项目版本 0.7.0 复制到我的博客存储库中。

从 GitHub 下载此博客文章代码

GitHub 上的 BlazorForms 项目

种子项目

BlazorForms 已作为 PRO CODERS PTY LTD 的内部项目开发了几年——一家总部位于澳大利亚、专注于高质量专家的咨询公司,现在我们决定将其开源分享给社区。

我们的框架将应用程序划分为 Flows(流程)、Forms(表单)和 Rules(规则)。这可以防止意大利面条式编码并减少运行时错误的数量,它还完全支持 Visual Studio 的智能感知。

为了演示每个组件的含义和外观,最好打开种子项目,让我们使用 Visual Studio 2022 来操作。

BlazorFormsSeed

该项目是使用 Visual Studio Blazor Server App 模板创建的,然后我们添加了 NuGet 包

  • BlazorForms 0.7.0
  • BlazorForms.Rendering.MudBlazorUI 0.7.0

它还间接引用了 MudBlazor 6.1.5——一个为 Blazor 实现 Material Design 的开源框架。

Picture 1

导航菜单和布局也已更改为使用 MudBlazor

当您运行应用程序时,您可以看到动态生成的简单表单,它绑定到 Model,支持验证,并且还是一个 Flow 中的一个步骤,该 Flow 控制显示哪个 Form 以及在 Form 提交或关闭时执行哪些操作。

Picture 2

所有示例代码都位于 Flows\SampleFlow.cs 文件中,为简洁起见,我们将几个类放在一起。

模型

在文件底部,您可以找到一个 Model 类,这对于这种方法至关重要。Model 由 Flow 和 Form 中使用的属性组成,编译器会检查您是否在代码中使用了现有属性和正确的类型。

    public class MyModel1 : IFlowModel
    {
        public virtual string? Message { get; set; }
        public virtual string? Name { get; set; }
        public virtual string? Logs { get; set; }
    }

Flows

当定义 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();
    }
}

Define 方法指定了一个步骤序列和条件分支,这些都共同控制了表示流程。

在 Sample Flow 中,我们定义了

  • 最初显示 QuestionForm,然后 Flow 将等待用户输入
  • 当按下 **Cancel** 按钮时,Flow 将终止
  • 当按下 **Submit** 按钮时,Flow 继续执行下一条语句 – If
  • If 语句中,Flow 检查条件(输入的名称等于“admin”)
  • 当输入“admin”时,将填充 Logs 属性,并显示 AdminForm
  • 当输入其他内容时,将填充 Message 属性,并显示 WellcomeForm

表单

Flow 中,我们使用了三个不同的 Form,它们将 UI 控件附加到 Model,该 Model 作为模板参数提供给泛型 class FormEditBase<>

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);
    }
}

QuestionFormDefine 方法中,我们有

  • 渲染 Form 副标题“BlazorForms Sample
  • 对于 Model 属性 Name,渲染必需的输入控件
  • 渲染“Cancel”按钮,按下时终止 Flow
  • 渲染“Submit”按钮,用于提交 Form 并继续 Flow

类似地,AdminForm 渲染一个只读文本区域,显示 Logs 属性,并且只有一个按钮,按下时终止 FlowWellcomeForm 渲染一个头部控件,显示 Message 属性和一个“Close”按钮。

您还记得,LogsMessage 属性的值是在 Flow 逻辑中填充的。

基本上,所有代码逻辑都包含在 Flows 和 Rules 中,而 Forms 只定义 Model 属性和应在 UI 中渲染的控件之间的绑定。

规则

Rules 可以附加到 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 属性。当用户在 Name 字段中输入“wombat”并按 **Tab** 键将焦点移至下一个控件时,Rule 将被触发,它将检查输入的 Name,并且 Message 将被显示。

图 3

Rules 也接受 Model 模板参数并支持类型安全,如果您使用不存在的 Model 属性或类型不匹配,您将看到编译错误。

Blazor 页面

在定义了 Flow、Forms 和 Rules 之后,我们就可以在 Blazor 页面上使用它们了。该项目中的 Pages 文件夹包含 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 的类型、Options 以及 Flow 完成后要导航到的位置。

当用户导航到“/sample”页面时,BlazorForms 框架会创建一个 SampleFlow 的实例并开始逐步执行它。当遇到第一个 Form 时,它会渲染 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 且可进行单元测试的逻辑放在 Flows 和 Rules 中;而 Forms 只包含 Model 和 UI 控件之间的绑定。

这篇文章是对 BlazorForms 的简要介绍,我没有涵盖不同类型的 Flows、如何在会话之间存储 Flow 状态、如何在 JSON 中定义 Flows 和 Forms(而不是 C#)以及许多其他功能。所有这些都将在我之后的博客中介绍。

PRO CODERS 团队认为,BlazorForms 框架甚至可以用于大型项目,其中需要以最少的精力和可接受的质量来实现和维护数百个表单。它应该是自定义 UI 实现的一个很好的替代方案,在自定义 UI 实现中,每个页面/表单都需要巨大的开发和测试工作量,并且随着时间的推移添加修改时质量会下降。

下一篇 – CrmLightDemoApp 种子项目

更复杂的场景将在稍后介绍,我们将开始查看 CrmLightDemoApp 种子项目。

它有几个与实现 CRUD 操作的 Repositories 相连接的 Flows,现在,我将展示一些截图。

Picture 4

Picture 5

Picture 6

您可以在我的 GitHub 上找到完整的解决方案代码,文件夹为 Story-08-BlazorForms-Intro-Seeds

感谢您的阅读,请记住,如果您在实施过程中需要任何帮助,可以随时与我们联系。

https://procoders.com.au/contact-us/

历史

  • 2023 年 1 月 9 日:初始版本
© . All rights reserved.