翻译自 Waqas Anwar 2021年3月21日的文章 《A Developer’s Guide to Blazor Data Binding》 [1]

现如今,大多数 Web 应用程序要么是在页面上显示某种数据,要么是使用表单从用户那里收集数据。这意味着每个 SPA 框架都必须支持数据绑定,以便开发者可以将数据与 labelform 控件等元素进行绑定。Blazor 组件内置了对数据绑定的支持,还使用了多种技术来同时支持单向和双向数据绑定。在本教程中,我将通过一个简单的卡片设计器示例来介绍 Blazor 数据绑定功能的基础知识,在该示例中,用户能够查看其卡片设计的实时更新情况。

下载源码[2]

单向绑定

在单向数据绑定中,数据沿一个方向传递。应用程序代码更新值以响应某些事件或用户操作,当值更新时,相应的 UI 也会动态更新。单向数据绑定中,不允许用户直接更改值。在 Blazor 中,我们通常使用 @ 符号后跟属性、字段,甚至是一个方法来实现单向数据绑定。例如,如果您的代码中有一个 Title 属性,并且您想将它与一个 h1 元素绑定,那么您可以编写类似以下代码段的代码。

<h1>@TItle</h1>

现在,要更新上述代码中的 Title,您可以使用一个简单的按钮 onclick 事件,调用代码中的 UpdateTitle 方法来更新 Title 属性的值。因为一旦用户点击按钮,更新的值便自动从代码传递到用户界面,所以 h1 元素的文本将会自动更新。

<button @onclick="UpdateTitle">Update Title</button>

@code{
public string Title { get; set; } = "Hello"; private void UpdateTitle()
{
Title = "Hello, Blazor!";
}
}

双向绑定

在双向数据绑定中,数据是双向流动的。通常,用户在前端以某种形式更新某个值,该值在后端代码中自动更新,然后这个新值再传递到 UI 并更新绑定到该值的所有元素。在 Blazor 中,可以使用 @bind 特性实现双向数据绑定,该特性能够以多种方式使用。下面的简单示例演示了 @bind 特性的基本用法,在这个示例中我们使用 @bind=Property 语法将 Title 属性与 input 元素进行绑定。

<h1>@Title</h1>

<input @bind="Title" />

@code {
public string Title { get; set; } = "Blazor";
}

我们还可以将某一属性绑定到特定的事件,以便仅在特定的事件触发时才更新该属性的值。绑定到特定事件的语法是 @bind:event="EVENT NAME"。例如,在下面的代码段中,我希望仅在用户将焦点从输入框移开时才改变 Title 属性。

<h1>@Title</h1>

<input @bind="Title" @bind:event="onchange" />

@code {
public string Title { get; set; } = "Blazor";
}

现在我们已经掌握了 Blazor 数据绑定的基础知识,那么,在接下来的教程中,我将向您展示一些使用数据绑定的真实示例。在我们开始之前,请确保您已熟悉了创建和使用 Blazor 组件。如果您不了解如何创建 Blazor 应用程序或组件,我建议您阅读我之前的文章 Blazor 组件入门指南

入门实例

在 Visual Studio 2019 中创建一个 Blazor Server 应用,并在 Pages 文件夹中添加一个新的 Blazor 组件 CardDesigner.razor。 我们想要构建一个简单的卡片设计器页面,允许用户同时设计和预览卡片。 让我们在新建组件的 razor 视图中添加以下 HTML 标记。

CardDesigner.razor

@page "/"

<h1>Card Designer (Blazor Data Binding)</h1> 

<div class="container">
<div class="row">
<div class="col-8">
<h3>Design</h3>
<form>
<div class="form-group">
<label for="Heading">Heading</label>
<input type="text" class="form-control" id="Heading">
</div>
<div class="form-group">
<label for="Description">Description</label>
<textarea class="form-control" id="Description" rows="4"></textarea>
</div>
<button class="btn btn-secondary mb-2">Reset</button>
</form>
</div>
<div class="col-4">
<h3>Preview</h3>
<div class="card bg-light w-100">
<div class="card-header">
Heading
</div>
<div class="card-body">
<p class="card-text">
Description
</p>
</div>
</div>
</div>
</div>
</div>

为了确保我们的卡片设计器看起来赏心悦目,您还需要在 wwwroot/css/site.css 文件中添加一些基本的 CSS 样式。

site.css

.container {
margin: 15px;
padding: 0px;
}
.col-8, .col-4 {
border: 1px solid #dadada;
padding: 10px;
}
h1 {
font-size: 22px;
font-weight: bold;
margin-bottom: 30px;
margin-top: 20px;
}
h3 {
font-size: 18px;
font-weight: bold;
margin-bottom: 25px;
}

运行该应用程序,您应该能看到类似以下内容的页面。左手边是设计部分,允许用户设置卡片的 HeadingDescription,右手边显示卡片预览。还有一个 Reset 按钮,可以将表单重置为默认值。

让我们为卡片设计器的实现逻辑创建一个单独的代码隐藏部分类(partial class)。该类有两个简单的带有默认值的属性 HeadingDescription。还有一个 ResetCard 方法,当用户点击 Reset 按钮时会调用此方法,将两个属性重置为其默认值。

CardDesigner.razor.cs

public partial class CardDesigner
{
public string Heading { get; set; } = "Heading";
public string Description { get; set; } = "Description"; public void ResetCard(MouseEventArgs e)
{
Heading = "Heading";
Description = "Description";
}
}

单向绑定实例

现在,我们已为查看 Blazor 数据绑定功能的实际应用做好了准备。让我们先从单向数据绑定开始。稍微更新一下上面的 <form> 代码,并使用 @ 符号和属性名添加单向绑定。我将 inputtextarea 元素的 value 特性(attribute)绑定到 HeadingDescription 属性(property),然后添加 @onchange 事件,使用 Lambda 表达式语法更改 Heading 属性。还将 ResetCard 方法附加到了 Reset 按钮的 onclick 事件。

CardDesigner.razor

<form>
<div class="form-group">
<label for="Heading">Heading</label>
<input type="text" class="form-control" id="Heading" value="@Heading"
@onchange="@(e => { Heading = e.Value.ToString(); })">
</div>
<div class="form-group">
<label for="Description">Description</label>
<textarea class="form-control" id="Description" rows="4"
@onchange="@(e => { Description = e.Value.ToString(); })" value="@Description"></textarea>
</div>
<button type="button" class="btn btn-secondary mb-2" @onclick="ResetCard">Reset</button>
</form>

我们还需要使用单向数据绑定更新预览部分的卡片,以便每次代码中的 HeadingDescription 更新时,预览部分都会自动在卡片上渲染更新后的值。

CardDesigner.razor

<div class="card text-white w-100 @SelectedStyleCssClass">
<div class="card-header">
@Heading
</div>
<div class="card-body">
<p class="card-text">
@Description
</p>
</div>
</div>

现在,如果您运行应用程序,您将会看到类似于下面的输出。尝试在设计区输入标题和描述,您会注意到,当您将焦点从输入框移开时,预览区会立即自动更新。

如果您不喜欢在 HTML 中使用 Lambda 表达式,您还可以在代码中定义 UpdateHeadingUpdateDescription 方法,然后将这些方法与 @onchange 事件关联起来。

CardDesigner.razor

<form>
<div class="form-group">
<label for="Heading">Heading</label>
<input type="text" class="form-control" id="Heading" value="@Heading"
@onchange="UpdateHeading">
</div>
<div class="form-group">
<label for="Description">Description</label>
<textarea class="form-control" id="Description" rows="4"
value="@Description"
@onchange="UpdateDescription"></textarea>
</div>
<button type="button" class="btn btn-secondary mb-2" @onclick="ResetCard">Reset</button>
</form>

CardDesigner.razor.cs

public partial class CardDesigner
{
public string Heading { get; set; } = "Heading";
public string Description { get; set; } = "Description"; public void ResetCard(MouseEventArgs args)
{
Heading = "Heading";
Description = "Description";
} public void UpdateHeading(ChangeEventArgs e)
{
Heading = e.Value.ToString();
} public void UpdateDescription(ChangeEventArgs e)
{
Description = e.Value.ToString();
}
}

双向绑定实例

截至目前,我们仅在应用程序中使用了单向绑定,因为 HeadingDescription 属性的值是在我们的代码中更新的,而且我们的代码只在用户将焦点从表单控件移开时才执行。让我们更新一下示例的代码,看看如何在该示例中使用双向数据绑定。使用 @bind 特性将 HeadingDescription 属性与表单控件绑定。我还希望当用户开始在表单控件中打字时立即更新卡片预览。为此,请将 @bind:event="oninput" 添加到了 inputtextarea 控件。

CardDesigner.razor

<form>
<div class="form-group">
<label for="Heading">Heading</label>
<input type="text" class="form-control" id="Heading" @bind="Heading" @bind:event="oninput">
</div>
<div class="form-group">
<label for="Description">Description</label>
<textarea class="form-control" id="Description" rows="4" @bind="Description" @bind:event="oninput"></textarea>
</div>
<button type="button" class="btn btn-secondary mb-2" @onclick="ResetCard">Reset</button>
</form>

现在,双向绑定已经设置好了,因此我们不再需要手动更新属性,这样我们就可以将 UpdateHeadingUpdateDescription 方法从代码中删除。

CardDesigner.razor.cs

public partial class CardDesigner
{
public string Heading { get; set; } = "Heading";
public string Description { get; set; } = "Description"; public void ResetCard(MouseEventArgs args)
{
Heading = "Heading";
Description = "Description";
}
}

再次运行应用程序并在设计表单中输入标题和描述,看下卡片预览是如何自动更新的。

让我们进一步扩展我们的示例,在设计区引入一个下拉列表控件。该下拉列表将显示不同的卡片样式,用户能够使用双向数据绑定即时地选择和应用任一卡片样式。让我们在 Data 文件夹中添加以下 StyleInfo 类。

StyleInfo.cs

public class StyleInfo
{
public string Name { get; set; }
public string CssClass { get; set; }
}

让我们在 CardDesigner.razor.cs 文件中再添加两个属性来存储可用卡片样式的列表,并存储所选样式的引用。我们在名为 OnInitialized 的组件初始化方法中初始化 Styles 属性。在从父组件接收到初始化参数后,组件会进行初始化,初始化完成时将调用 OnInitialized 方法。

CardDesigner.razor.cs

public partial class CardDesigner
{
public string Heading { get; set; } = "Heading";
public string Description { get; set; } = "Description";
public List<StyleInfo> Styles { get; set; }
public string SelectedStyleCssClass { get; set; } protected override void OnInitialized()
{
Styles = new List<StyleInfo>()
{
new StyleInfo() { Name = "Primary", CssClass = "bg-primary" },
new StyleInfo() { Name = "Secondary", CssClass = "bg-secondary" },
new StyleInfo() { Name = "Success", CssClass = "bg-success" }
}; SelectedStyleCssClass = "bg-primary";
} public void ResetCard(MouseEventArgs args)
{
Heading = "Heading";
Description = "Description";
}
}

最后,我们需要在 CardDesigner.razor 文件中添加一个 HTML select 元素。我们运行一个简单的 @foreach 循环来迭代 Styles 属性,并在循环中创建 <option> 元素。每个 <option> 元素的 value 特性使用 CssClass 属性值呈现,每个 <option> 元素的文本使用 Name 属性值呈现。

CardDesigner.razor

<div class="form-group">
<label for="Style">Style</label>
<select class="form-control" id="Style" @bind="SelectedStyleCssClass" @bind:event="onchange">
@foreach (var style in Styles)
{
<option value="@style.CssClass">@style.Name</option>
}
</select>
</div>

在上面的代码片段中,我们使用 @bind 特性将 SelectedStyleCssClass 属性与 select 元素绑定,并指定使用 selectonchange 事件,以便每次用户从下拉列表中选择一个选项时,卡片样式自动更新。

现在,如果您运行项目,将会看到下拉列表中填充的样式,并且选中的样式会应用到预览部分的卡片。

右键点击 select 元素并选择 检查(Inspect) 菜单选项,可以查看 option 是如何渲染在 HTML 中的,以及每个 optionvalue 是如何包含我们在代码中初始化的 CssClass 属性的。

试试从下拉列表中选择不同的样式,卡片预览会立即更新。

总结

在本教程中,我介绍了 Blazor 数据绑定的基础知识。我们学习了如何使用单向和双向数据绑定功能,以及如何使用数据绑定更新值。我们还学习了如何利用不同的事件来指定何时更新值。在 Blazor 中还有一些更高级的数据绑定概念,我将尽最大的努力就这个主题再写几篇文章。

相关阅读:

作者 : Waqas Anwar

翻译 : 技术译站

链接 : 英文原文


  1. https://www.ezzylearning.net/tutorial/a-developers-guide-to-blazor-data-binding A Developer’s Guide to Blazor Data Binding

  2. https://github.com/ezzylearning/BlazorDataBindingDemo 下载源码

Blazor 数据绑定开发指南的更多相关文章

  1. Blazor 事件处理开发指南

    翻译自 Waqas Anwar 2021年3月25日的文章 <A Developer's Guide To Blazor Event Handling> [1] 如果您正在开发交互式 We ...

  2. Blazor 路由及导航开发指南

    翻译自 Waqas Anwar 2021年4月2日的文章 <A Developer's Guide To Blazor Routing and Navigation> [1] 检查传入的请 ...

  3. Blazor 模板化组件开发指南

    翻译自 Waqas Anwar 2021年4月15日的文章 <A Developer's Guide To Blazor Templated Components> [1] 在我之前的一篇 ...

  4. Blazor 组件库开发指南

    翻译自 Waqas Anwar 2021年5月21日的文章 <A Developer's Guide To Blazor Component Libraries> [1] Blazor 的 ...

  5. ASP.NET Aries 开源开发框架:开发指南(一)

    前言: 上周开源了Aries开发框架后,好多朋友都Download了源码,在运行过程里,有一些共性的问题会问到. 所以本篇打算写一下简单的开发指南,照顾一下不是太看的懂源码的同学,同时也会讲解一下框架 ...

  6. FreeMarker模板开发指南知识点梳理

    freemarker是什么? 有什么用? 怎么用? (问得好,这些都是我想知道的问题) freemarker是什么? FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生 ...

  7. Jetty使用教程(四:21-22)—Jetty开发指南

    二十一.嵌入式开发 21.1 Jetty嵌入式开发HelloWorld 本章节将提供一些教程,通过Jetty API快速开发嵌入式代码 21.1.1 下载Jetty的jar包 Jetty目前已经把所有 ...

  8. JVM 平台上的各种语言的开发指南

    JVM 平台上的各种语言的开发指南 为什么我们需要如此多的JVM语言? 在2013年你可以有50中JVM语言的选择来用于你的下一个项目.尽管你可以说出一大打的名字,你会准备为你的下一个项目选择一种新的 ...

  9. iOS原生地图开发指南续——大头针与自定义标注

    iOS原生地图开发指南续——大头针与自定义标注 出自:http://www.sxt.cn/info-6042-u-7372.html 在上一篇博客中http://my.oschina.net/u/23 ...

随机推荐

  1. 痞子衡嵌入式:在SBL项目实战中妙用i.MXRT1xxx里SystemReset不复位的GPR寄存器

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1xxx里SystemReset不复位的GPR寄存器的小妙用. 我们知道稍大规模的项目代码设计一般都是多人协作完成的,在项目 ...

  2. 向pom.xml中配置Maven使用JDK8编译

    maven项目会用maven-compiler-plugin默认的jdk版本来进行编译,如果不指明版本就容易出现版本不匹配的问题,可能导致编译不通过的问题. 解决办法:在pom文件中配置maven-c ...

  3. Prometheus监控软件部署方法

    背景:负责基于区块链的某公正项目的状态上报模块设计编码,基于Prometheus进行二次开发 1.说明Prometheus 是一个开源的服务监控软件,它通过 HTTP 协议从远程机器收集数据并存储在本 ...

  4. GO学习-(37) 使用Air实现Go程序实时热重载

    使用Air实现Go程序实时热重载 今天我们要介绍一个神器--Air能够实时监听项目的代码文件,在代码发生变更之后自动重新编译并执行,大大提高gin框架项目的开发效率. 为什么需要实时加载? 之前使用P ...

  5. CVPR2019论文观察:感知边缘检测的双向级联网络

    CVPR2019论文观察:感知边缘检测的双向级联网络 BDCN:Bi-Directional Cascade Network for Perceptual Edge Detection 摘要 探索多尺 ...

  6. TorchScript神经网络集成技术

    TorchScript神经网络集成技术 create_torchscript_neuropod 将TorchScript模型打包为neuropod包. create_torchscript_neuro ...

  7. 基于Linux的TCP网络聊天室

    1.实验项目名称:基于Linux的TCP网络聊天室 2.实验目的:通过TCP完成多用户群聊和私聊功能. 3.实验过程: 通过socket建立用户连接并传送用户输入的信息,分别来写客户端和服务器端,利用 ...

  8. SpringBoot系列——cache缓存

    前言 日常开发中,缓存是解决数据库压力的一种方案,通常用于频繁查询的数据,例如新闻中的热点新闻,本文记录springboot中使用cache缓存. 官方文档介绍:https://docs.spring ...

  9. JAVA面向对象详细总结

    面向对象概念   所有操作基于对象进行操作实现 面向对象的三大特征   封装.继承.多态 类:具有相同特征和行为物体的统称 在java中类的定义语法: [修饰符]   class   类名{   属性 ...

  10. 【渗透实战】sqlmap_修改tamper脚本_绕过WAF_第三期

    /文章作者:Kali_MG1937 CSDN博客号:ALDYS4 QQ:3496925334/ 今天google找注入点的时候发现某企业一个挺有意思的waf 常规操作绕过去后决定写一篇博客 信息收集 ...