Blazor University 组件 — 级联值

炒沙作縻终不饱,缕冰文章费工巧。这篇文章主要讲述Blazor University 组件 — 级联值相关的知识,希望能为你提供帮助。

原文链接:https://blazor-university.com/components/cascading-values/
级联值源代码[1]
我们已经看到 Blazor 如何允许我们使用参数[2]将上下文从父组件传递给子组件。随着组件变得越来越复杂,将其拆分为子组件的情况并不少见。在某些时候,一个组件可能会要求其使用者传递它自身不使用但它的一个子组件需要的状态。随着我们组件的结构随着时间的推移变得越来越复杂,我们可能会发现自己的组件需要添加多个参数,而这些参数并不被使用,而是简单地传递,因为它们在更深层次的某个地方需要。
Blazor University 组件 — 级联值

文章图片

以求职申请为例。一个 ??Vacancy??(空缺) 可以有很多 ??Applications??(申请);每份 ??Application?? 针对一个 ??Vacancy??,属于一个 ??Candidate??(候选人);??Vacancy?? 和 ??Candidate?? 都有一个 ??Address??(地址)。
【Blazor University 组件 — 级联值】
Blazor University 组件 — 级联值

文章图片

查看空缺显示所有申请。在某些时候,需要允许用户单击单个申请并在申请详情页面上详细查看它,因此创建了一个新的 ViewApplication.razor 组件,该组件将在查看空缺或查看单个申请时使用.
Blazor University 组件 — 级联值

文章图片

现在我们有一个 ViewVacancy.razor 组件(标记为 A),它遍历所有针对空缺的申请,并为每个申请呈现一个 ViewApplication.razor 组件(标记为 B)。
作为标准化应用程序的练习,决定应使用 ViewCandidate.razor 组件(标记为 C)显示候选人,并且应使用 ViewAddress.razor 组件(标记为 D)显示所有地址。
Blazor University 组件 — 级联值

文章图片

为了机会平等,显示空缺申请的页面需要在不透露候选人姓名或完整地址的情况下查看申请的选项,因此在“查看匿名数据”页面中添加了一个复选框。事实上,这个功能被认为对应用程序非常重要,复选框被添加到 MainLayout.razor 页面,因此它在整个系统的任何地方都可用。
Blazor University 组件 — 级联值

文章图片

ViewVacancy.razor 组件没有敏感数据,因此它不需要知道用户是否正在查看匿名数据。其中的 ViewApplication.razor 组件也没有敏感信息,所以它也不需要知道;但是 ViewCandidate.razor 组件需要匿名候选人的姓名,而 ViewCandidate.razor 组件中的 ViewAddress.razor 组件也需要匿名数据。
Blazor University 组件 — 级联值

文章图片

因为 ViewAddress.razor 和 ViewCandidate.razor 需要一个布尔参数来标识它们是否应该显示敏感信息,因此某些组件也必须需要相同的参数才能将其直接或间接传递给它托管的任何组件。
Blazor University 组件 — 级联值

文章图片

仅将数据传递给子级所需的参数的图示
这是用级联值解决的挑战。
按名称级联值源代码[3]
指定级联参数的值非常简单。在我们的 Razor html 标记中的任何时候,我们都可以创建一个 ??CascadingValue?? 元素。该元素内呈现的所有内容都可以访问指定的值。
@page "/"

< h1> Toggle the options< /h1>
< input @bind-value=https://www.songbingjia.com/android/FirstOptionValue type="checkbox" /> First option
< br />
< input @bind-value=https://www.songbingjia.com/android/SecondOptionValue type="checkbox" /> Second option
< br />

< CascadingValue Name="FirstOption" Value=https://www.songbingjia.com/android/@FirstOptionValue>
< CascadingValue Name="SecondOption" Value=https://www.songbingjia.com/android/@SecondOptionValue>
< FirstLevelComponent />
< /CascadingValue>
< /CascadingValue>

@code
bool FirstOptionValue;
bool SecondOptionValue;

使用级联值同样简单。任何组件,无论它在 ??CascadingValue??? 元素中的嵌套程度如何,都可以通过使用 ??CascadingParameter?? 属性修饰的属性来访问该值。
< ul>
< li> FirstOption = @FirstOption< /li>
< li> SecondOption = @SecondOption< /li>
< /ul>

@code
[CascadingParameter(Name="FirstOption")]
private bool FirstOptionget; set;

[CascadingParameter(Name="SecondOption")]
private bool SecondOptionget; set;

请注意,我们使用该值的属性的名称是无关紧要的。Blazor 不会查找在 ??CascadingValue??? 元素中指定的同名属性;我们可以随意命名我们的属性,它实际上用的是 ??CascadingParameterAttribute??? 上的 ??Name?? ,它标识应该注入哪个级联值。
将充当级联参数的属性的可见性设置为私有是一种很好的做法。允许他们通过代码对使用者进行设置是不合逻辑的,因为该值实际上由设置 ??Cascading?? 值的父级所有。
按类型级联值源代码[4]
之前我们看到了如何通过名称级联一个值。设置名称很重要,因为它用于通过匹配名称来将 ??CascadingValue??? 中指定的值推送到使用组件的正确属性中。另一种选择是在不指定名称的情况下指定 ??CascadingValue??,当 Blazor 遇到以这种方式指定的级联值时,如果属性满足以下条件,它会将其值注入到组件的属性中。
  1. 该属性使用??CascadingPropertyAttribute?? 进行装饰。
  2. [CascadingProperty] 没有指定名称。
  3. 该属性与 [CascadingValue] 中设置的类型相同(例如布尔值)。
  4. 该属性有一个设置器。
  5. 该属性是 public 的。
例如,以下 ??CascadingValue??? 将匹配 ??SomeComponent??? 中的两个 ??CascadingParameter?? 属性。
< CascadingValue Value=https://www.songbingjia.com/android/@true>
< SomeComponent/>
< /CascadingValue>

Property1 = @Property1
Property2 = @Property2

@code

[CascadingParameter]
private bool Property1get; set;

[CascadingParameter]
private bool Property2get; set;

未命名的 ??CascadingValue??? 不如指定了 ??Name??? 的 ??CascadingValue??? 那样具体,因为每个具有正确类型且没有 ??Name??? 的 ??CascadingParameter??? 修饰属性都会使用该值。在我们定义一个简单的 .NET 类型(例如 ??bool??? 或 ??int??)的情况下,建议我们使用命名参数,但是,有时值的类型足以识别其用途;指定名称将是多余的,因此排除它可以节省一点时间。
随着求职申请的增长,我们最终可能会得到多个级联参数,例如:
  • ??bool ViewAnonymizedData??指示是否应隐藏个人身份信息。
  • ??string DateFormat??使用组件可以使用它以统一的方式格式化日期。
  • ??string LanguageCode??组件可以使用它来显示翻译后的文本。
这里出现的明显模式是这些都与用户的偏好有关。而不是使用带有多个 ??CascadingValue?? 元素的 Razor 标记,如下所示:
< CascadingValue Name="ViewAnonymizedData" Value=https://www.songbingjia.com/android/@ViewAnonymizedData>
< CascadingValue Name="DateFormat" Value=https://www.songbingjia.com/android/@DateFormat>
< CascadingValue Name="LanguageCode" Value=https://www.songbingjia.com/android/@LanguageCode>
(Body goes here)
< /CascadingValue>
< /CascadingValue>
< /CascadingValue>

拥有一个自定义类会更有意义(并且需要更少的代码):
public class UserPreferences

public bool ViewAnonymizedDataget; set;
public string DateFormatget; set;
public string LanguageCodeget; set;

然后像这样创建你的 Razor 标记:
< CascadingValue Value=https://www.songbingjia.com/android/@UserPreferences>
< /CascadingValue>

然后,使用组件只需要一个标记为 ??[CascadingParameter]?? 的属性,而不是三个。
@if (!UserPreferences.ViewAnonymizedData)

< div>
< span> Name< /span> @Candidate.Name
< /div>
< div>
< span> Date of birth< /span> @Candidate.DateOfBirth.ToString(UserPreferences.DateFormat)
< /div>
< ViewAddress Address=@Candidate.Address/>

else

< span> [Anonmymized view]< /span>


@code

[CascadingParameter]
private UserPreferences UserPreferencesget; set;

当然,这个例子忽略了如何根据 ??UserPreferences.LanguageCode?? 翻译静态文本。
重写级联值级联值和级联参数允许它们的值向下级联渲染树,而无需从父级显式传递到子级。Blazor 的另一个特性是它允许我们在渲染树的下方重写 ??CascadingValue?? 的值。
给定以下 ??ViewSomeValue??? 组件,该组件显示名为 ??ValueToOverride??? 的 ??CascadingValue?? 的值:
< div> Values are @SomeValue1 / @SomeValue2< /div>

@code

[CascadingParameter(Name = "CascadedValue")]
private string SomeValue1get; set;

[CascadingParameter(Name = "ValueToOverride")]
private string SomeValue2get; set;

以及使用该组件的以下页面:
@page "/overridden"

< CascadingValue Name="CascadedValue" Value=https://www.songbingjia.com/android/@CascadedValue>
< CascadingValue Name="ValueToOverride" Value=https://www.songbingjia.com/android/@OuterValue>

< h2> First level< /h2>
< ViewSomeValue />

< CascadingValue Name="ValueToOverride" Value=https://www.songbingjia.com/android/@InnerValue>
< h2> Second level< /h2>
< ViewSomeValue />
< /CascadingValue>

< h2> Back to first level< /h2>
< ViewSomeValue />

< /CascadingValue>
< /CascadingValue>

@code

string CascadedValue = "https://www.songbingjia.com/android/CascadedValue";
string OuterValue = "https://www.songbingjia.com/android/Outer value";
string InnerValue = "https://www.songbingjia.com/android/Inner value";

我们看到以下输出:
Blazor University 组件 — 级联值

文章图片

请注意第三个组件的 ??ValueToOverride?? 值如何自动恢复为“Outer value”。这是因为该值是由元素的深度决定的。第三个组件在最外面的   ??CascadingValue?? 中呈现,因此它是它找到的最近的包含匹配值的父级。
还要注意 ??CascadedValue?? 的值如何可用于所有组件。
Blazor University 组件 — 级联值

文章图片

参考资料
[1]
源代码: https://github.com/mrpmorris/blazor-university/tree/master/src/CascadingValues/ManualParameterPassing
?
[3]
源代码: https://github.com/mrpmorris/blazor-university/tree/master/src/CascadingValues/CascadingValuesByName
[4]
源代码: https://github.com/mrpmorris/blazor-university/tree/master/src/CascadingValues/CascadingValuesByType



    推荐阅读