Value 和 @bind-Value 之间的区别是什么?

huangapple go评论59阅读模式
英文:

Difference between Value and @bind-Value?

问题

我正在查看有关 InputCheckBox https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.forms.inputcheckbox 的文档,我看到它公开了 Value 以绑定到所需的布尔值("获取或设置输入的值。应与双向绑定一起使用。")。然而,到处都是人们使用 @bind-Value,此外,我无法使 Value 工作。

这个:

<InputCheckbox @bind-Value="model.IsSelected"></InputCheckbox>

与这个有何不同(为什么这个不起作用):

<InputCheckbox Value="@model.IsSelected"></InputCheckbox>

我还注意到 @bind-Value 会更新/通知模型有关更改,并更新任何依赖于 IsSelected 的属性,而 Value 不会(除非明确指定?)。
另外,当使用 Value 时,我需要为标签包括一个 ValueExpression(否则它不会呈现)。这个 ValueExpression 是什么?在哪些情况下会有人实现不同的 ValueExpression

使用 Value 有什么好处吗?如何使其工作?我有遗漏什么吗?

英文:

I am looking at the docs for an InputCheckBox https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.forms.inputcheckbox, and I see that it exposes Value to be bound to a desired boolean (Gets or sets the value of the input. This should be used with two-way binding.). Nonetheless, everywhere, people are using @bind-Value instead, Moreover, I cannot get Value to work.

How is this:

&lt;InputCheckbox @bind-Value=&quot;model.IsSelected&quot;&gt;&lt;/InputCheckbox&gt;

Different from this (And why this one does not work):

&lt;InputCheckbox Value=&quot;@model.IsSelected&quot;&gt;&lt;/InputCheckbox&gt;

I also noted that @bind-Value updates/notifies the model about the changes and updates any property that depends on IsSelected, while Value does not (probably unless explicitly specified?).
Additionally, when using Value, I need to also include a ValueExpression for the tag (or it won't render). What this ValueExpression?? In which scenarios would someone implement a different ValueExpression?

Has using Value any benefit? What will it take to make it work? Am I missing something here?

答案1

得分: 5

以下是翻译好的内容:

背景信息和 InputBase 的解释。

所有继承 InputBase 的组件都实现了三个参数:

  1. Value 是控件的“输入”值 - 它是强类型的。
  2. ValueChanged 是控件的“输出”值:一个带有强类型值的回调函数。
  3. ValueExpression 是一个定义实际模型对象/属性的 Func 委托。 它在内部用于创建一个 FieldIdentifier 对象,该对象用于在 EditContextValidationStore 中标识属性。

此页面演示了两种设置绑定的方式。

第一种是手动设置并将更改链接到回调方法。 当您希望除了设置值之外运行其他代码时,可以使用此方法(我正在设置时间戳)。

第二种使用由 Razor 提供的“语法糖”。 @bind-Value 告诉 Razor 编译器构建一组代码,以将三个参数与一个名为 Value 的公共属性链接到提供的模型属性。

在编译的低级别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<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

英文:

Some more background information and an explanation of InputBase.

All InputBase inherited components implement three Parameters:

  1. Value is the "in" value for the control - it's strongly typed.
  2. ValueChanged is the "out" value for the control: A callback with a strongly typed value.
  3. ValueExpression is a Func delegate that defines the actual model object/property. It's used internally to create a FieldIdentifier object, which is used to identify the property in the EditContext and ValidationStore.

This page demonstrates two ways of setting up the bind.

The first does it manually and hooks up the change to a callback method. You use this when you have other code you want to run in addition to just setting the value. (I'm setting a time stamp).

The second uses "syntatic sugar" provided by Razor. @bind-Value tells the Razor compiler to build out a set of code to link the three Parameters with a common name of Value to te provided model property.

@page &quot;/&quot;

&lt;PageTitle&gt;Index&lt;/PageTitle&gt;

&lt;h1&gt;Hello, world!&lt;/h1&gt;

&lt;InputCheckbox class=&quot;form-check&quot;
               @bind-Value=this.model.Value /&gt;

&lt;InputCheckbox class=&quot;form-check&quot;
               Value=this.model.Value
               ValueChanged=this.OnValueChanged
               ValueExpression=&quot;() =&gt; this.model.Value&quot; /&gt;

&lt;div class=&quot;alert alert-info&quot;&gt;
    Value: @this.model.Value
&lt;/div&gt;

&lt;div class=&quot;alert alert-info&quot;&gt;
    @this.message
&lt;/div&gt;

@code {
    private Model model = new();
    private string message = &quot;No Message&quot;;

    private Task OnValueChanged(bool value)
    {
        this.model.Value = value;
        // You can do other stuff here if you need to
        this.message = $&quot;Set at {DateTime.Now.ToLongTimeString()}&quot;;
        return Task.CompletedTask;
    }

    public class Model
    {
        public bool Value { get; set; }
    }
}

In the compiled low level C# code they are virtually the same thing.

Here's the full bind:

private RenderFragment FirstComponent =&gt; __builder =&gt;
{
    __builder.OpenComponent&lt;InputCheckbox&gt;(5);
    __builder.AddAttribute(6, &quot;class&quot;, &quot;form-check&quot;);
    __builder.AddAttribute(7, &quot;Value&quot;, RuntimeHelpers.TypeCheck&lt;Boolean&gt;(this.model.Value));
    __builder.AddAttribute(8, &quot;ValueChanged&quot;, RuntimeHelpers.TypeCheck&lt;EventCallback&lt;Boolean&gt;&gt;(EventCallback.Factory.Create&lt;Boolean&gt;(this, RuntimeHelpers.CreateInferredEventCallback(this, __value =&gt; this.model.Value = __value, this.model.Value))));
    __builder.AddAttribute(9, &quot;ValueExpression&quot;, RuntimeHelpers.TypeCheck&lt;global::System.Linq.Expressions.Expression&lt;System.Func&lt;System.Boolean&gt;&gt;&gt;(() =&gt; this.model.Value));
    __builder.CloseComponent();
};

Here's the manual bind:

private RenderFragment SecondComponent =&gt; __builder =&gt;
{
    __builder.OpenComponent&lt;InputCheckbox&gt;(11);
    __builder.AddAttribute(12, &quot;class&quot;, &quot;form-check&quot;);
    __builder.AddAttribute(13, &quot;Value&quot;, RuntimeHelpers.TypeCheck&lt;global::System.Boolean&gt;(this.model.Value));
    __builder.AddAttribute(14, &quot;ValueChanged&quot;, RuntimeHelpers.TypeCheck&lt;EventCallback&lt;Boolean&gt;&gt;(EventCallback.Factory.Create&lt;Boolean&gt;(this, this.OnValueChanged)));
    __builder.AddAttribute(15, &quot;ValueExpression&quot;, RuntimeHelpers.TypeCheck&lt;Expression&lt;System.Func&lt;System.Boolean&gt;&gt;&gt;(() =&gt; this.model.Value));
    __builder.CloseComponent();
};

Net7.0 @input-value:get and @input-value:set

Net7.0 implements more syntatic sugar to let you do binding in yet another way. It also adds a third @input-value:after bind to provide a method to do the timestamp I showed above.

See this for the latest bind information - https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding

答案2

得分: 3

如您所注意,@bind-Value 提供了对 Value 的双向绑定。

我曾经创建了以下演示:

  • 从模板中新建一个项目

  • 稍微修改计数器页面:

<p role="status">当前计数:@Count</p>

<button class="btn btn-primary" @onclick="IncrementCount">点击我</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>计数器1@count1</p>
    <p>计数器2@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;
    }
}

现在,当您在主页上单击按钮时,两个计数器实例的行为完全相同。

这是因为对于 @bind-Count,Razor 编译器在后台生成了与 CountChanged 参数名称等效的 UpdateCount1 部分。这仅在存在正确名称的回调参数时才有效:CountChanged

请参阅Blazor数据绑定

英文:

As you noticed, @bind-Value delivers 2-way binding for Value.

I made the following demo once:

  • Start a new Project from one of the templates

  • Change the Counter Page a little:

&lt;p role=&quot;status&quot;&gt;Current count: @Count&lt;/p&gt;

&lt;button class=&quot;btn btn-primary&quot; @onclick=&quot;IncrementCount&quot;&gt;Click me&lt;/button&gt;

@code {
    [Parameter]
    public int Count { get; set; } = 1;

    [Parameter]
    public EventCallback&lt;int&gt; CountChanged { get; set; }

    public Task IncrementCount()
    {
        return CountChanged.InvokeAsync(Count + 1);        
    }
}
  • And then on the the Index page:
@page &quot;/&quot;
&lt;div&gt;
    &lt;p&gt;Counter1 : @count1&lt;/p&gt;
    &lt;p&gt;Counter2 : @count2&lt;/p&gt;
&lt;/div&gt;

&lt;Counter @bind-Count=&quot;count1&quot;  /&gt;

&lt;Counter Count=&quot;count2&quot; CountChanged=&quot;UpdateCount2&quot; /&gt;

@code {
    int count1 = 1;
    int count2 = 2;

    void UpdateCount2(int newValue)
    {
        count2 = newValue;
    }
}

When you now click the buttons on the Index page both Counter instances behave exactly the same.

This is because for @bind-Count the Razor compiler generates the UpdateCount1 part (equivalent) behind the scenes. And that only works when there is a callback parameter with the right name: CountChanged.

See Blazor data binding

huangapple
  • 本文由 发表于 2023年2月16日 07:32:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75466407.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定