我正在查看
InputCheckBox
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.forms.inputcheckbox 的文档,我发现它公开了 Value
绑定到所需的布尔值 (Gets or sets the value of the input. This should be used with two-way binding.
)。尽管如此,世界各地的人们都在使用 @bind-Value
来代替,而且,我无法让 Value
工作。
这怎么样:
<InputCheckbox @bind-Value="model.IsSelected"></InputCheckbox>
与此不同(以及为什么这个不起作用):
<InputCheckbox Value="@model.IsSelected"></InputCheckbox>
我还注意到
@bind-Value
更新/通知模型有关更改并更新依赖于 IsSelected
的任何属性,而 Value
则不会(可能除非明确指定?)。
此外,当使用 Value
时,我还需要为标签添加 ValueExpression
(否则它不会渲染)。这是啥ValueExpression
??在什么情况下有人会实施不同的ValueExpression
?
使用
Value
有什么好处吗?需要什么才能让它发挥作用?我在这里错过了什么吗?
更多背景信息和解释
InputBase
。
所有
InputBase
继承的组件都实现三个Parameters
:
Value
是控件的“in”值 - 它是强类型的。ValueChanged
是控件的“out”值:具有强类型值的回调。ValueExpression
是定义实际模型对象/属性的 Func
委托。它在内部用于创建一个 FieldIdentifier
对象,该对象用于标识 EditContext
和 ValidationStore
中的属性。此页面演示了两种设置绑定的方法。
第一个手动执行此操作并将更改连接到回调方法。当您除了设置值之外还想运行其他代码时,可以使用此选项。 (我正在设置时间戳)。
第二种使用
Razor
提供的“合成糖”。 @bind-Value
告诉 Razor 编译器构建一组代码,将通用名称为 Value
的三个参数链接到提供的模型属性。
@page "/"
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
<InputCheckbox class="form-check"
@bind-Value=this.model.Value />
<InputCheckbox class="form-check"
Value=this.model.Value
ValueChanged=this.OnValueChanged
ValueExpression="() => this.model.Value" />
<div class="alert alert-info">
Value: @this.model.Value
</div>
<div class="alert alert-info">
@this.message
</div>
@code {
private Model model = new();
private string message = "No Message";
private Task OnValueChanged(bool value)
{
this.model.Value = value;
// You can do other stuff here if you need to
this.message = $"Set at {DateTime.Now.ToLongTimeString()}";
return Task.CompletedTask;
}
public class Model
{
public bool Value { get; set; }
}
}
在编译后的低级 C# 代码中,它们实际上是相同的东西。
这是完整的绑定:
private RenderFragment FirstComponent => __builder =>
{
__builder.OpenComponent<InputCheckbox>(5);
__builder.AddAttribute(6, "class", "form-check");
__builder.AddAttribute(7, "Value", RuntimeHelpers.TypeCheck<Boolean>(this.model.Value));
__builder.AddAttribute(8, "ValueChanged", RuntimeHelpers.TypeCheck<EventCallback<Boolean>>(EventCallback.Factory.Create<Boolean>(this, RuntimeHelpers.CreateInferredEventCallback(this, __value => this.model.Value = __value, this.model.Value))));
__builder.AddAttribute(9, "ValueExpression", RuntimeHelpers.TypeCheck<global::System.Linq.Expressions.Expression<System.Func<System.Boolean>>>(() => this.model.Value));
__builder.CloseComponent();
};
这是手动绑定:
private RenderFragment SecondComponent => __builder =>
{
__builder.OpenComponent<InputCheckbox>(11);
__builder.AddAttribute(12, "class", "form-check");
__builder.AddAttribute(13, "Value", RuntimeHelpers.TypeCheck<global::System.Boolean>(this.model.Value));
__builder.AddAttribute(14, "ValueChanged", RuntimeHelpers.TypeCheck<EventCallback<Boolean>>(EventCallback.Factory.Create<Boolean>(this, this.OnValueChanged)));
__builder.AddAttribute(15, "ValueExpression", RuntimeHelpers.TypeCheck<Expression<System.Func<System.Boolean>>>(() => this.model.Value));
__builder.CloseComponent();
};
Net7.0 @input-value:get 和 @input-value:set
Net7.0 实现了更多的语法糖,让您以另一种方式进行绑定。它还添加了第三个
@input-value:after
绑定,以提供一种方法来执行上面显示的时间戳。
请参阅此处以获取最新的绑定信息 - https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding
正如您所注意到的,
@bind-Value
为 Value 提供 2 路绑定。
我做了一次以下演示:
从模板之一启动一个新项目
稍微更改计数器页面:
<p role="status">Current count: @Count</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
[Parameter]
public int Count { get; set; } = 1;
[Parameter]
public EventCallback<int> CountChanged { get; set; }
public Task IncrementCount()
{
return CountChanged.InvokeAsync(Count + 1);
}
}
@page "/"
<div>
<p>Counter1 : @count1</p>
<p>Counter2 : @count2</p>
</div>
<Counter @bind-Count="count1" />
<Counter Count="count2" CountChanged="UpdateCount2" />
@code {
int count1 = 1;
int count2 = 2;
void UpdateCount2(int newValue)
{
count2 = newValue;
}
}
当您现在单击索引页面上的按钮时,两个 Counter 实例的行为完全相同。
这是因为对于
@bind-Count
,Razor 编译器会在幕后生成 UpdateCount1
部分(等效)。仅当存在具有正确名称的回调参数时才有效:CountChanged
。
请参阅 Blazor 数据绑定