ASP.NET Core Blazor 数据绑定ASP.NET Core Blazor data binding

本文内容

作者:Luke LathamDaniel Roth

Razor 组件通过名为 @bind 的 HTML 元素特性提供了数据绑定功能,该特性具有字段、属性或 Razor 表达式值。

下面的示例将 CurrentValue 属性绑定到文本框的值:

  1. <input @bind="CurrentValue" />
  2. @code {
  3. private string CurrentValue { get; set; }
  4. }

当文本框失去焦点时,该属性的值会更新。

仅当呈现组件时(而不是响应属性值更改),才会在 UI 中更新文本框。由于组件会在事件处理程序代码执行之后呈现自己,因此在触发事件处理程序之后,通常会 在 UI 中反映属性更新。

@bindCurrentValue 属性结合使用 (<input @bind="CurrentValue" />) 在本质上等效于以下内容:

  1. <input value="@CurrentValue"
  2. @onchange="@((ChangeEventArgs __e) => CurrentValue =
  3. __e.Value.ToString())" />
  4. @code {
  5. private string CurrentValue { get; set; }
  6. }

呈现组件时,输入元素的 value 来自 CurrentValue 属性。用户在文本框中键入并更改元素焦点时,会激发 onchange 事件并将 CurrentValue 属性设置为更改的值。实际上,代码生成更加复杂,因为 @bind 会处理执行类型转换的情况。原则上,@bind 将表达式的当前值与 value 属性关联,并使用注册的处理程序处理更改。

通过同时包含带有 event 参数的 @bind:event 属性,在其他事件上绑定属性或字段。以下示例在 oninput 事件上绑定 CurrentValue 属性:

  1. <input @bind="CurrentValue" @bind:event="oninput" />
  2. @code {
  3. private string CurrentValue { get; set; }
  4. }

与在元素失去焦点时激发的 onchange 不同,oninput 在文本框的值更改时激发。

通过 @bind-{ATTRIBUTE}:event 语法使用 @bind-{ATTRIBUTE} 可绑定除 value 之外的元素属性。在下面的示例中,当 _paragraphStyle 值更改时,段落的样式会更新:

  1. @page "/binding-example"
  2. <p>
  3. <input type="text" @bind="_paragraphStyle" />
  4. </p>
  5. <p @bind-style="_paragraphStyle" @bind-style:event="onchange">
  6. Blazorify the app!
  7. </p>
  8. @code {
  9. private string _paragraphStyle = "color:red";
  10. }

属性绑定是区分大小写的。例如,@bind 有效,而 @Bind 无效。

无法分析的值Unparsable values

如果用户向数据绑定元素提供无法分析的值,则在触发绑定事件时,无法分析的值会自动还原为以前的值。

请参考以下方案:

  • <input> 元素绑定到 int 类型,其初始值为 123
  1. <input @bind="MyProperty" />
  2. @code {
  3. [Parameter]
  4. public int MyProperty { get; set; } = 123;
  5. }
  • 用户在页面中将该元素的值更新为 123.45,并更改元素焦点。

在上面的方案中,元素的值会还原为 123如果拒绝值 123.45 以采用原始值 123,则用户会了解其值不被接受。

默认情况下,绑定适用于元素的 onchange 事件 (@bind="{PROPERTY OR FIELD}")。使用 @bind="{PROPERTY OR FIELD}" @bind:event={EVENT} 对其他事件触发绑定。对于 oninput 事件 (@bind:event="oninput"),在任何引入无法分析的值的击键之后,会进行还原。当使用 int 绑定类型以 oninput 事件为目标时,会阻止用户键入 . 字符。. 字符会立即删除,因此用户会收到仅允许整数的即时反馈。在某些情况下,在 oninput 事件中还原值并不理想,例如在应该允许用户清除无法解析的 <input> 值时。替代方案包括:

  • 不使用 oninput 事件。使用默认 onchange 事件(仅指定 @bind="{PROPERTY OR FIELD}"),其中无效值在元素失去焦点之前不会还原。
  • 绑定到可以为 null 的类型(如 int?string),并提供自定义逻辑来处理无效条目。
  • 使用窗体验证组件,如 InputNumberInputDate。窗体验证组件具有用于管理无效输入的内置支持。窗体验证组件:
    • 允许用户提供无效输入并在关联的 EditContext 上接收验证错误。
    • 在 UI 中显示验证错误,而不干扰用户输入其他 webform 数据。

格式字符串Format strings

数据绑定使用 @bind:format 处理 DateTime 格式字符串。目前无法使用其他格式表达式,如货币或数字格式。

  1. <input @bind="StartDate" @bind:format="yyyy-MM-dd" />
  2. @code {
  3. [Parameter]
  4. public DateTime StartDate { get; set; } = new DateTime(2020, 1, 1);
  5. }

在前面的代码中,<input> 元素的字段类型 (type) 默认为 text对于绑定以下 .NET 类型,支持 @bind:format

@bind:format 属性指定要应用于 <input> 元素的 value 的日期格式。该格式还用于在 onchange 事件发生时分析值。

不建议为 date 字段类型指定格式,因为 Blazor 具有用于设置日期格式的内置支持。尽管提出了建议,但如果使用 date 字段类型提供格式,则只有使用 yyyy-MM-dd 日期格式才能使绑定正常工作:

  1. <input type="date" @bind="StartDate" @bind:format="yyyy-MM-dd">

使用组件参数的父级到子级绑定Parent-to-child binding with component parameters

绑定可识别组件参数,其中 @bind-{PROPERTY} 可以将属性值从父组件向下绑定到子组件。使用链接绑定的子级到父级绑定部分中,介绍了从子级绑定到父级。

以下子组件 (ChildComponent) 具有 Year 组件参数和 YearChanged 回调:

  1. <h2>Child Component</h2>
  2. <p>Year: @Year</p>
  3. @code {
  4. [Parameter]
  5. public int Year { get; set; }
  6. [Parameter]
  7. public EventCallback<int> YearChanged { get; set; }
  8. }

EventCallback<T>ASP.NET Core Blazor 事件处理 中进行了说明。

以下父组件使用:

  • ChildComponent 并将 ParentYear 参数从父级绑定到子组件上的 Year 参数。
  • onclick 事件用于触发 ChangeTheYear 方法。有关详细信息,请参阅 ASP.NET Core Blazor 事件处理
  1. @page "/ParentComponent"
  2. <h1>Parent Component</h1>
  3. <p>ParentYear: @ParentYear</p>
  4. <ChildComponent @bind-Year="ParentYear" />
  5. <button class="btn btn-primary" @onclick="ChangeTheYear">
  6. Change Year to 1986
  7. </button>
  8. @code {
  9. [Parameter]
  10. public int ParentYear { get; set; } = 1978;
  11. private void ChangeTheYear()
  12. {
  13. ParentYear = 1986;
  14. }
  15. }

加载 ParentComponent 会生成以下标记:

  1. <h1>Parent Component</h1>
  2. <p>ParentYear: 1978</p>
  3. <h2>Child Component</h2>
  4. <p>Year: 1978</p>

如果通过在 ParentComponent 中选择按钮来更改 ParentYear 属性的值,则会更新 ChildComponentYear 属性。当重新呈现 ParentComponent 时,Year 的新值会呈现在 UI 中:

  1. <h1>Parent Component</h1>
  2. <p>ParentYear: 1986</p>
  3. <h2>Child Component</h2>
  4. <p>Year: 1986</p>

Year 参数是可绑定的,因为它具有与 Year 参数类型相匹配的伴随 YearChanged 事件。

按照约定,<ChildComponent @bind-Year="ParentYear" /> 在本质上等效于编写:

  1. <ChildComponent @bind-Year="ParentYear" @bind-Year:event="YearChanged" />

通常,可以通过包含 @bind-{PROPRETY}:event 特性将属性绑定到对应的事件处理程序。例如,可以使用以下两个特性将属性 MyProp 绑定到 MyEventHandler

  1. <MyComponent @bind-MyProp="MyValue" @bind-MyProp:event="MyEventHandler" />

使用链接绑定的子级到父级绑定Child-to-parent binding with chained bind

一种常见方案是将数据绑定参数链接到组件输出中的页面元素。此方案称为链接绑定 ,因为多个级别的绑定会同时进行。

无法在页面元素中使用 @bind 语法实现链接绑定。必须单独指定事件处理程序和值。但是,父组件可以将 @bind 语法用于组件的参数。

以下 PasswordField 组件 (PasswordField.razor ):

  • <input> 元素的值设置为 Password 属性。
  • 使用 EventCallback 向父组件公开 Password 属性的更改。
  • 使用 onclick 事件触发 ToggleShowPassword 方法。有关详细信息,请参阅 ASP.NET Core Blazor 事件处理
  1. <h1>Child Component</h2>
  2. Password:
  3. <input @oninput="OnPasswordChanged"
  4. required
  5. type="@(_showPassword ? "text" : "password")"
  6. value="@Password" />
  7. <button class="btn btn-primary" @onclick="ToggleShowPassword">
  8. Show password
  9. </button>
  10. @code {
  11. private bool _showPassword;
  12. [Parameter]
  13. public string Password { get; set; }
  14. [Parameter]
  15. public EventCallback<string> PasswordChanged { get; set; }
  16. private Task OnPasswordChanged(ChangeEventArgs e)
  17. {
  18. Password = e.Value.ToString();
  19. return PasswordChanged.InvokeAsync(Password);
  20. }
  21. private void ToggleShowPassword()
  22. {
  23. _showPassword = !_showPassword;
  24. }
  25. }

PasswordField 组件在另一个组件中使用:

  1. @page "/ParentComponent"
  2. <h1>Parent Component</h1>
  3. <PasswordField @bind-Password="_password" />
  4. @code {
  5. private string _password;
  6. }

对前面示例中的密码执行检查或捕获错误:

  • Password 创建支持字段(在下面的示例代码中为 _password)。
  • Password 资源库中执行检查或捕获错误。

如果密码的值中使用了空格,则以下示例会向用户提供即时反馈:

  1. @page "/ParentComponent"
  2. <h1>Parent Component</h1>
  3. Password:
  4. <input @oninput="OnPasswordChanged"
  5. required
  6. type="@(_showPassword ? "text" : "password")"
  7. value="@Password" />
  8. <button class="btn btn-primary" @onclick="ToggleShowPassword">
  9. Show password
  10. </button>
  11. <span class="text-danger">@_validationMessage</span>
  12. @code {
  13. private bool _showPassword;
  14. private string _password;
  15. private string _validationMessage;
  16. [Parameter]
  17. public string Password
  18. {
  19. get { return _password ?? string.Empty; }
  20. set
  21. {
  22. if (_password != value)
  23. {
  24. if (value.Contains(' '))
  25. {
  26. _validationMessage = "Spaces not allowed!";
  27. }
  28. else
  29. {
  30. _password = value;
  31. _validationMessage = string.Empty;
  32. }
  33. }
  34. }
  35. }
  36. [Parameter]
  37. public EventCallback<string> PasswordChanged { get; set; }
  38. private Task OnPasswordChanged(ChangeEventArgs e)
  39. {
  40. Password = e.Value.ToString();
  41. return PasswordChanged.InvokeAsync(Password);
  42. }
  43. private void ToggleShowPassword()
  44. {
  45. _showPassword = !_showPassword;
  46. }
  47. }

单选按钮Radio buttons

有关绑定到窗体中的单选按钮的信息,请参阅 ASP.NET Core Blazor 窗体和验证