ASP.NET Core Blazor Webassembly 之 数据绑定

简介:

ASP.NET Core Blazor Webassembly 之 数据绑定

上一次我们学习了Blazor组件相关的知识(Asp.net Core Blazor Webassembly - 组件)。这次继续学习Blazor的数据绑定相关的知识。当代前端框架都离不开数据绑定技术。数据绑定技术以数据为主导来驱动UI界面,用户对数据的修改会实时提现在UI上,极大的提高了开发效率,让开发者从繁琐的dom操作中解脱出来。对于数据绑定.NET开发者并不会陌生,WPF里大量应用数据绑定技术,有过WPF开发经验的同学其实很容易理解前端的数据绑定。总之数据绑定技术及其概念、思维极其重要。下面让我们看看Blazor的数据绑定技术。

单向绑定
Blazor的数据绑定官方文档是直接从双向绑定开始的,但我觉得有必要说一下单向绑定。因为其他框架一般都会区分单向、双向,比如vue的v-bind单向,v-model就是双向。我们这里分开讲也有利于跟其他框架进行对比。下面我们实现一个计数器组件来演示下单向数据绑定。

使用@进行绑定
@page "/counter"

Current count: @currentCount

@code {

private int currentCount = 0;

private void IncrementCount()
{
    currentCount++;
}

}

这个Counter组件默认的项目就自带。跟我们使用服务端Razor一样,使用@符号在需要替换值的地方插入对应的变量。这个值就会被渲染在相应的地方。当我们在前端修改变量的时候,对应的ui界面会同步进行修改。

使用@bind-{attribute}进行绑定
除了直接使用@进行绑定,我们还可以使用@bind-{attribute}来实现对html元素属性的绑定,比如对style,class内容进行绑定。下面演示下对class进行绑定。我们把p元素的class绑定到“currentClass”字段。

@page "/counter"

Counter

current count: @currentCount

@code {

private string currentClass = "text-danger";

private int currentCount = 0;

private void IncrementCount()
{
    currentCount++;
}

}

使用@bind-{attribute}进行绑定有个比较奇怪的问题,当你使用@bind-{attribute}进行绑定的时候必须同时指定@bind-{attribute}:event。@bind-{attribute}:event是用来指定双向绑定的时候控件在发生某个事件的时候回写值到绑定的字段上。可是p,div这种元素根本不可能会激发onchange,oninput这种事件,也不可能去修改绑定的字段的值,这个用法感觉有点多此一举。
Blazor的单向数据绑定的用法跟ASP.NET Core MVC的Razor基本相似,不同点就是Blazor不需要Http回发到服务器就可以实时渲染新的界面出来。

双向绑定
双向绑定主要使用在一些输入控件上,比如input,select等。当我们对这些控件上的值进行修改后会回写绑定的字段。这种特性在表单场景中非常有用。我们定义一个用户信息编辑的组件来演示下:

@page "/infoedit"

userName: @userName


sex: @sex


userName: <input @bind="userName" />


sex:
<select @bind="sex">
    <option value="m">男</option>
    <option value="f">女</option>
</select>

@code {

private string userName="abc";
private string sex="f";

}

当我们运行这个组件,在文本框进行修改后,鼠标点击其他地方让文本框失去焦点值就会回写到绑定的字段上,上面的单向绑定信息会自动同步。但是如果你用过VUE或者Angularjs的双向绑定就会觉得失去焦点再回写字段数据太慢了,一点也不酷。要知道VUE的双向绑定可是实时同步的,那么Blazor如何做到在输入的同时就更新值呢,答案是使用@bind:event来指定回写的激发事件,我们改成“oninput”事件就可以实现:

userName: <input @bind="userName" @bind:event="oninput"/>

双向绑定的多种写法
看到这里也许你也明白了,@bind真正的本质是由对value的绑定和对某个事件的绑定协同完成的。这点跟VUE非常相似。@bind其实是@bind-value的缩写,我们可以用@bind-value来实现双向绑定:

userName: <input @bind-value="userName" @bind-value:event="oninput"/>


以上写法的效果跟@bind一模一样。再进一步,@bind-value也只是对@的包装,我们可以使用@来实现双向绑定:

@page "/infoedit"

userName: @userName


sex: @sex


userName: <input value="@userName" @oninput="oninput"/>


sex:
<select @bind="sex">
    <option value="m">男</option>
    <option value="f">女</option>
</select>

@code {

private string userName="abc";
private string sex="f";

private void oninput(ChangeEventArgs e)
{
    userName = e.Value.ToString();
}

}
以上代码的效果跟@bind一模一样。通过使用@对value直接进行绑定以及绑定一个oninput事件进行值的回写,同样实现了双向绑定。

格式化时间字符串
使用@bind:format 可以对绑定时间类型字段的时候进行格式化:

出生日期:

这个功能有点类似Angularjs的filter功能,但是目前只能对时间进行格式化,功能很弱。

父组件绑定数据到子组件
组件之间往往都是嵌套的,很多子组件都依赖父组件的数据来决定如何呈现,这种场景非常常见。我们还是继续修改上面的编辑组件,用户信息不在自己初始化,而是从父组件传递过来:
子组件:

====================child==================

userName: <input @bind="UserInfo.UserName" />


sex:
<select @bind="UserInfo.Sex">
    <option value="m">男</option>
    <option value="f">女</option>
</select>

BrithDay:<input @bind="UserInfo.BrithDay" />


@code {
[Parameter]
public UserInfo UserInfo { get; set; }

[Parameter]
public EventCallback<UserInfo> UserInfoChanged { get; set; }

}
子组件定义一个UserInfo对象并且使用[Parameter]进行标记,同时如果父组件使用@bind-UserInfo来绑定的话,还必须实现一个UserInfoChanged事件。
父组件:

@page "/"
====================parent==================

userName: @userInfo.UserName


sex: @userInfo.Sex


brithday: @userInfo.BrithDay

@code {

private UserInfo userInfo;

protected override void OnInitialized()
{
    userInfo = new UserInfo
    {
        UserName = "abc",
        Sex = "f",
        BrithDay = DateTime.Now
    };
    base.OnInitialized();
}

}

父组件初始化一个UserInfo对象后通过@bind-UserInfo绑定给子组件。注意这里我们修改子组件的值并不会同步给父组件,所以可以看到@bind-UserInfo的传值还是单向的。

子组件传值给父组件 ??
原来我以为父组件使用@bind-UserInfo并且子组件实现了对应的changed方法就可以实现子组件跟父组件的自动传值,就跟input的双向绑定一样。但是不管我怎么试都没有卵用。如果只是单向的那为什么要这么大费周章?我直接使用属性赋值不就可以了么?像下面这样:


直接通过组件的属性直接把父组件的数据传递到子组件,效果跟上面是一样的,而且这样子组件我还能少写一个changed事件。我原本以为使用基本类型,比如string可以自动双向绑定,然后并没有什么卵用。没有办法我继续尝试父组件监听UserInfoChanged事件来接受子组件的数据,然后VS提示我同一个事件不能绑定两次。

我已经无语了,难道要我再定义一个事件吗?于是我放弃了@bind-来实现子组件给父组件传值,我直接使用属性赋值难道不比这个简单吗?
子组件修改数据的时候不断对外抛事件:

====================child==================

userName: <input @bind="UserInfo.UserName"  @oninput="InvokeChanged"/>

sex:
<select @bind="UserInfo.Sex">
    <option value="m">男</option>
    <option value="f">女</option>
</select>

BrithDay:<input @bind="UserInfo.BrithDay" />


@code {
[Parameter]
public UserInfo UserInfo { get; set; }

[Parameter]
public EventCallback<UserInfo> UserInfoChanged { get; set; }

private void InvokeChanged()
{
    UserInfoChanged.InvokeAsync(this.UserInfo);
    Console.WriteLine("InvokeChanged");
}

}
父组件监听事件后更新数据:

@page "/"
====================parent`==================

userName: @userInfo.UserName


sex: @userInfo.Sex


brithday: @userInfo.BrithDay


title: @title

@code {

private UserInfo userInfo;

private string title;

protected override void OnInitialized()
{
    userInfo = new UserInfo
    {
        UserName = "abc",
        Sex = "f",
        BrithDay = DateTime.Now
    };
    base.OnInitialized();
}

private void HandleUserInfoChanged(UserInfo info)
{
    this.userInfo.UserName = info.UserName;

    Console.WriteLine("HandleUserInfoChanged");
}

}

我原以为这样就没什么问题了,可奇怪的是,父组件页面重新渲染需要在子组件第二次修改数据后呈现且呈现的是前一次的。

到这里我已经无语了,最后我只能在子组件直接添加一个按钮,修改完后点击保存来触发InvokeChanged事件,这样子是可以的:

====================child==================

userName: <input @bind="UserInfo.UserName" />

sex:
<select @bind="UserInfo.Sex">
    <option value="m">男</option>
    <option value="f">女</option>
</select>

BrithDay:<input @bind="UserInfo.BrithDay" />

@code {

[Parameter]
public UserInfo UserInfo { get; set; }

[Parameter]
public EventCallback<UserInfo> UserInfoChanged { get; set; }

private void InvokeChanged()
{
    UserInfoChanged.InvokeAsync(this.UserInfo);
    Console.WriteLine("InvokeChanged");
}

}

到此数据绑定也演示完了,可是关于子组件往父组件传值的事我实在没像明白,难道是我哪里错了?

最后附上代码:BlazorWasmDataBind

作者:Agile.Zhou(kklldog)

原文地址https://www.cnblogs.com/kklldog/p/blazor-wasm-databind.html

相关文章
|
11天前
|
数据可视化 网络协议 C#
C#/.NET/.NET Core优秀项目和框架2024年3月简报
公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附带项目和框架源码地址)。注意:排名不分先后,都是十分优秀的开源项目和框架,每周定期更新分享(欢迎关注公众号:追逐时光者,第一时间获取每周精选分享资讯🔔)。
|
3月前
|
开发框架 前端开发 JavaScript
盘点72个ASP.NET Core源码Net爱好者不容错过
盘点72个ASP.NET Core源码Net爱好者不容错过
70 0
|
3月前
|
开发框架 .NET
ASP.NET Core NET7 增加session的方法
ASP.NET Core NET7 增加session的方法
37 0
|
1月前
|
开发框架 人工智能 .NET
C#/.NET/.NET Core拾遗补漏合集(持续更新)
C#/.NET/.NET Core拾遗补漏合集(持续更新)
|
1月前
|
开发框架 中间件 .NET
C# .NET面试系列七:ASP.NET Core
## 第一部分:ASP.NET Core #### 1. 如何在 controller 中注入 service? 在.NET中,在ASP.NET Core应用程序中的Controller中注入服务通常使用<u>依赖注入(Dependency Injection)</u>来实现。以下是一些步骤,说明如何在Controller中注入服务: 1、创建服务 首先,确保你已经在应用程序中注册了服务。这通常在Startup.cs文件的ConfigureServices方法中完成。例如: ```c# services.AddScoped<IMyService, MyService>(); //
60 0
|
2月前
|
开发框架 前端开发 .NET
福利来袭,.NET Core开发5大案例,30w字PDF文档大放送!!!
为了便于大家查找,特将之前开发的.Net Core相关的五大案例整理成文,共计440页,32w字,免费提供给大家,文章底部有PDF下载链接。
32 1
福利来袭,.NET Core开发5大案例,30w字PDF文档大放送!!!
|
2月前
|
算法 BI API
C#/.NET/.NET Core优秀项目和框架2024年1月简报
C#/.NET/.NET Core优秀项目和框架2024年1月简报
|
2月前
|
SQL 开发框架 前端开发
ASP.NET WEB项目中GridView与Repeater数据绑定控件的用法
ASP.NET WEB项目中GridView与Repeater数据绑定控件的用法
32 0
|
3月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
38 0
|
1月前
|
开发框架 前端开发 .NET
C# .NET面试系列六:ASP.NET MVC
<h2>ASP.NET MVC #### 1. MVC 中的 TempData\ViewBag\ViewData 区别? 在ASP.NET MVC中,TempData、ViewBag 和 ViewData 都是用于在控制器和视图之间传递数据的机制,但它们有一些区别。 <b>TempData:</b> 1、生命周期 ```c# TempData 的生命周期是短暂的,数据只在当前请求和下一次请求之间有效。一旦数据被读取,它就会被标记为已读,下一次请求时就会被清除。 ``` 2、用途 ```c# 主要用于在两个动作之间传递数据,例如在一个动作中设置 TempData,然后在重定向到另
95 5