当前位置: 首页 > news >正文

Bootstrap Blazor 实战动态表单组件

1.新建工程

源码

新建工程b18ValidateForm,使用 nuget.org 进行 BootstrapBlazor 组件安装, Chart 库,字体. 将项目添加到解决方案中

dotnet new blazorserver -o b18ValidateForm
dotnet add b06chart package BootstrapBlazor
dotnet add b06chart package BootstrapBlazor.FontAwesome
dotnet sln add b18ValidateForm/b18ValidateForm.csproj

2.样式表和Javascript 引用

增加主题样式表到 Pages/_Layout.cshtml 文件中

删除 <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />

并在下面添加三行

<link href="_content/BootstrapBlazor.FontAwesome/css/font-awesome.min.css" rel="stylesheet" />
<link href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css" rel="stylesheet" />

添加 Javascript 引用到 Pages/_Layout.cshtml 文件中

<script src="_framework/blazor.server.js"></script> 之前添加

<script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js" asp-append-version="true"></script>

3.添加增加命名空间引用到 _Imports.razor 文件中

@using BootstrapBlazor.Components

4.增加 BootstrapBlazorRoot 组件到 App.razor 文件中

<BootstrapBlazorRoot><Router AppAssembly="@typeof(App).Assembly">...</Router>
</BootstrapBlazorRoot>

5.添加BootstrapBlazor服务到 Program.cs 文件中

builder.Services.AddSingleton<WeatherForecastService>(); 后加入

builder.Services.AddBootstrapBlazor();

6.添加EditorForm测试代码

Index.razor

<EditorForm Model="@Model"><FieldItems><EditorItem @bind-Field="@context.Name" /><EditorItem @bind-Field="@context.Education" /><EditorItem @bind-Field="@context.Complete" /></FieldItems><Buttons><Button Icon="fa-solid fa-floppy-disk" Text="提交" /></Buttons>
</EditorForm>

Index.razor.cs

using BootstrapBlazor.Components;
using Microsoft.Extensions.Localization;
using System.Collections.Concurrent;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;namespace b18ValidateForm.Pages;public sealed partial class Index
{[NotNull]private Foo? Model { get; set; }/// <summary>/// <inheritdoc/>/// </summary>protected override void OnInitialized(){Model = new Foo(){Name = "",Count = 1,Address = "TestAddress",DateTime = new DateTime(1997, 12, 05),Education = EnumEducation.Middle};}}
Demo示例数据
/// <summary>
/// Demo示例数据
/// Demo sample data
/// </summary>
public class Foo
{// 列头信息支持 Display DisplayName 两种标签/// <summary>////// </summary>[Display(Name = "主键")][AutoGenerateColumn(Ignore = true)]public int Id { get; set; }/// <summary>////// </summary>[Required(ErrorMessage = "{0}不能为空")][AutoGenerateColumn(Order = 10, Filterable = true, Searchable = true)][Display(Name = "姓名")]public string? Name { get; set; }/// <summary>////// </summary>[AutoGenerateColumn(Order = 1, FormatString = "yyyy-MM-dd", Width = 180)][Display(Name = "日期")]public DateTime? DateTime { get; set; }/// <summary>////// </summary>[Display(Name = "地址")][Required(ErrorMessage = "{0}不能为空")][AutoGenerateColumn(Order = 20, Filterable = true, Searchable = true)]public string? Address { get; set; }/// <summary>////// </summary>[Display(Name = "数量")][Required][AutoGenerateColumn(Order = 40, Sortable = true)]public int Count { get; set; }/// <summary>////// </summary>[Display(Name = "是/否")][AutoGenerateColumn(Order = 50)]public bool Complete { get; set; }/// <summary>////// </summary>[Required(ErrorMessage = "请选择学历")][Display(Name = "学历")][AutoGenerateColumn(Order = 60)]public EnumEducation? Education { get; set; }/// <summary>////// </summary>[Required(ErrorMessage = "请选择一种{0}")][Display(Name = "爱好")][AutoGenerateColumn(Order = 70, Editable = false)]public IEnumerable<string> Hobby { get; set; } = new List<string>();#region Static methods/// <summary>/// /// </summary>protected static readonly Random Random = new();/// <summary>/// 生成Foo类,随机数据/// Generate Foo class, random data/// </summary>/// <param name="localizer"></param>/// <returns></returns>public static Foo Generate(IStringLocalizer<Foo> localizer) => new(){Id = 1,Name = localizer["Foo.Name", "1000"],DateTime = System.DateTime.Now,Address = localizer["Foo.Address", $"{Random.Next(1000, 2000)}"],Count = Random.Next(1, 100),Complete = Random.Next(1, 100) > 50,Education = Random.Next(1, 100) > 50 ? EnumEducation.Primary : EnumEducation.Middle};/// <summary>/// 生成 Foo 类,随机数据/// Generate Foo class, random data/// </summary>/// <returns>返回一个Foo类的List,Return a List of Foo class</returns>public static List<Foo> GenerateFoo(int count = 80) => Enumerable.Range(1, count).Select(i => new Foo(){Id = i,Name = "Foo.Name"+ $"{i:d4}",DateTime = System.DateTime.Now.AddDays(i - 1),Address = "Foo.Address"+$"{Random.Next(1000, 2000)}",Count = Random.Next(1, 100),Complete = Random.Next(1, 100) > 50,Education = Random.Next(1, 100) > 50 ? EnumEducation.Primary : EnumEducation.Middle}).ToList();/// <summary>/// 通过 Count 获得颜色/// </summary>/// <param name="count"></param>/// <returns></returns>public static Color GetProgressColor(int count) => count switch{>= 0 and < 10 => Color.Secondary,>= 10 and < 20 => Color.Danger,>= 20 and < 40 => Color.Warning,>= 40 and < 50 => Color.Info,>= 50 and < 70 => Color.Primary,_ => Color.Success};/// <summary>/// 通过 Id 获取 Title/// </summary>/// <returns></returns>private static string GetTitle() => Random.Next(1, 80) switch{>= 1 and < 10 => "Clerk",>= 10 and < 50 => "Engineer",>= 50 and < 60 => "Manager",>= 60 and < 70 => "Chief",_ => "General Manager"};/// <summary>/// /// </summary>/// <param name="id"></param>/// <returns></returns>public static string GetTitle(int id) => Cache.GetOrAdd(id, key => GetTitle());/// <summary>/// /// </summary>/// <returns></returns>public static Func<IEnumerable<Foo>, string, SortOrder, IEnumerable<Foo>> GetNameSortFunc() => Utility.GetSortFunc<Foo>();private static ConcurrentDictionary<int, string> Cache { get; } = new();#endregion
}/// <summary>
///
/// </summary>
public enum EnumEducation
{/// <summary>////// </summary>[Display(Name = "小学")]Primary,/// <summary>////// </summary>[Display(Name = "中学")]Middle
}

7.运行

8.新需求: 在点击[是/否]的时候,动态控制姓名和地址栏只读

尝试把代码改为

<EditorForm Model="@Model"><FieldItems>@*<InputDIY Context="@context" />*@@if (context.Complete){<EditorItem @bind-Field="@context.Name" Readonly="@context.Complete" /><EditorItem @bind-Field="@context.Education" Readonly="@context.Complete" />}<EditorItem @bind-Field="@context.DateTime" Readonly="true" /><EditorItem @bind-Field="@context.Complete" /></FieldItems><Buttons><Button Icon="fa-solid fa-floppy-disk" Text="提交" /></Buttons>
</EditorForm>

运行之, 并没有达到预期. 无论怎么改变[是/否]检查框,姓名和地址栏都是可写的,因为渲染机制问题,所以要改一下思路.

正确方法是把逻辑包成一个组件,组件里面就可以局部刷新达到预期效果

9.新建组件 InputDIY.razor


<Row><BootstrapInput @bind-Value="@Context!.Name" IsDisabled="@Context!.Complete" ShowLabel="true" /><BootstrapInput @bind-Value="@Context!.Education" IsDisabled="@Context!.Complete" ShowLabel="true" /> </Row><br />@code{[Parameter] public Foo? Context { get; set; }}

Index.razor代码改为

<EditorForm Model="@Model"><FieldItems><InputDIY Context="@context" /><EditorItem @bind-Field="@context.Name" Editable="@context.Complete" /><EditorItem @bind-Field="@context.Education" Editable="@context.Complete" /><EditorItem @bind-Field="@context.DateTime" Readonly="true" /><EditorItem @bind-Field="@context.Complete" /></FieldItems><Buttons><Button Icon="fa-solid fa-floppy-disk" Text="提交" /></Buttons>
</EditorForm>

注:如果不加入以下写法,会照成InputDIY里面渲染一次Name列,FieldItems又渲染一次Name列.这是MS的内部机制一个小坑,暂时没有办法避开.

<EditorItem @bind-Field="@context.Name" Editable="@context.Complete" />

10.运行效果

11.数据验证 ValidateForm

<ValidateForm Model="@Model"><EditorForm TModel="Foo"><FieldItems><InputDIY Context="@context" /><EditorItem @bind-Field="@context.Name" Editable="@context.Complete" /><EditorItem @bind-Field="@context.Education" Editable="@context.Complete" /><EditorItem @bind-Field="@context.DateTime" Readonly="true" /><EditorItem @bind-Field="@context.Complete" /></FieldItems><Buttons><Button ButtonType="ButtonType.Submit" Icon="fa-solid fa-floppy-disk" Text='提交' /></Buttons></EditorForm>
</ValidateForm>

12.DEMO源码

http://www.lryc.cn/news/139214.html

相关文章:

  • Elasticsearch 集成---Spark Streaming 框架集成
  • Kotlin 中的 协程 基础篇
  • SQL事务
  • 关于flutter中 initState() 与 setState() 用法
  • 智能电话机器人是如何自主学习的
  • 【Rust】Rust学习 第十八章模式用来匹配值的结构
  • 我的学习笔记:数据处理
  • GB28181国标平台测试软件NTV-GBC(包含服务器和模拟客户端)
  • 云原生:重塑企业的技术疆界
  • 华为星闪,一项将 “ 更稳 WiFi ” 和 “ 更好蓝牙 ” 融合起来的通信标准
  • IDEA创建Mybatis格式XML文件
  • 二叉树中的最大路径和-递归
  • Python if-else 速记
  • Python使用内置的json模块来处理JSON数据
  • 亿赛通电子文档安全管理系统 RCE漏洞
  • 信息安全面试题合集
  • vue 简单实验 自定义组件 传参数 props
  • 目标检测笔记(十一):如何结合特定区域进行目标检测(基于OpenCV的人脸检测实例)
  • PID直观感受简述
  • Tomcat运行后localhost:8080访问自己编写的网页
  • 传感网应用开发1+X实训室建方案
  • PDF校对:让您的文件无瑕疵
  • SpringBoot--解决空字符串转枚举异常
  • Redis的常用数据类型详解
  • jpa里IdentityGenerator和IncrementGenerator的区别
  • 基于element UI 实现 table 列 拖拽
  • (GPT、GEE)遥感云大数据、洪涝灾害监测、红树林遥感制图、河道轮廓监测、洪涝灾害监测、GRACE重力卫星、源遥感影像
  • vue中实现将页面或者div内容导出为pdf格式
  • Ubuntu 配置国内源
  • 分布式核心知识