上一篇写数据绑定的文章,写到最后留了一个坑。当子组件绑定父组件的一个字段,并且子组件修改它的时候父组件不能实时进行同步更新UI的问题,最近终于在Blazui作者的指导下搞定了。
UserInfo类要实现INotifyPropertyChanged接口
代码语言:javascript复制 public class UserInfo: INotifyPropertyChanged
{
private string _userName;
public string UserName {
get
{
return _userName;
}
set
{
_userName = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(UserName)));
}
}
public string Sex { get; set; }
public DateTime BrithDay { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
没想到微软blazor还是借用了WPF搞MVVM的模式,模型需要实现INotifyPropertyChanged类,在属性发生修改的时候可以发出通知。
父组件订阅PropertyChanged事件:
代码语言:javascript复制@page "/"
====================parent```==================
<p>
userName: @userInfo.UserName
</p>
<p>
sex: @userInfo.Sex
</p>
<p>
brithday: @userInfo.BrithDay
</p>
<p>
title: @title
</p>
<InfoEdit UserInfo="userInfo" UserInfoChanged="HandleUserInfoChanged"></InfoEdit>
@code {
private UserInfo userInfo;
private string title;
protected override void OnInitialized()
{
userInfo = new UserInfo
{
UserName = "abc",
Sex = "f",
BrithDay = DateTime.Now
};
this.userInfo.PropertyChanged = (o, e) => StateHasChanged();
base.OnInitialized();
}
private void HandleUserInfoChanged(UserInfo info)
{
this.userInfo = info;
Console.WriteLine("HandleUserInfoChanged");
}
}
父组件订阅子组件的PropertyChanged事件,当事件发生的时候调用组件的StateHasChanged方法。StateHasChanged方法会通知组件说状态发生变化了,也就是说组件会被重新渲染。这就是最关键的东西了。
子组件
代码语言:javascript复制====================child==================
<p>
userName: <input @bind="UserInfo.UserName" @bind:event="oninput" />
</p>
<p>
sex:
<select @bind="UserInfo.Sex">
<option value="m">男</option>
<option value="f">女</option>
</select>
</p>
<p>
BrithDay:<input @bind="UserInfo.BrithDay" />
</p>
<button class="btn btn-danger" @onclick="InvokeChanged">保存</button>
@code {
[Parameter]
public UserInfo UserInfo { get; set; }
[Parameter]
public EventCallback<UserInfo> UserInfoChanged { get; set; }
private void InvokeChanged()
{
UserInfoChanged.InvokeAsync(this.UserInfo);
Console.WriteLine("InvokeChanged");
}
}
运行
一些吐槽
虽然搞定了子父组件同步的问题,但是我不能理解的是,为什么微软要搞的这么复杂。使用@bind-UserInfo会强制用户在子组件实现一个 EventCallback UserInfoChanged 事件。那么既然@bind:event="oninput"可以实时回写字段的值,那么为什么不直接同时调用UserInfoChanged对外抛事件呢?而且在父组件同样可以在编译器直接植入对UserInfoChanged事件的监听同时刷新UI。可能是微软为了性能,想要用户手工控制父组件的渲染时机吧。