请注意,对于那些希望了解Blazor如何“在引擎盖下”工作的人来说,这是一个高级话题。为了每天使用Blazor,并不需要知道这些信息-但我觉得了解内部情况会很有帮助。
让我们从描述Blazor如何维护表单数据的元状态的UML图开始。
image.png

EditContext

每当EditForm.Model更改(表单中正在修改的对象)时,都会执行EditForm.OnParametersSet并创建一个新的EditContext实例。EditForm组件将此EditContext声明为级联值,以便表单中的任何组件都可以访问它。
EditContext是当前正在编辑的对象的表单元数据持有者。在表单中编辑对象(如Person时,Blazor需要了解有关该对象的其他信息,以便提供更丰富的用户体验。Blazor持有的其他信息告诉我们:

  • 模型的特定属性是否已手动更改。
  • 哪些模型属性存在验证错误,以及这些错误是什么。

显然,正在编辑的模型的类应该只代表我们的特定业务需求,所以让我们的模型类实现这个额外的用户界面状态信息将会有冲突-所以Blazor将这个额外的信息本身存储在EditContext中。这就是EditForm在其Model更改时创建新EditContext的原因,因为如果Model更改,则EditContext中保存的信息不再相关。

FieldIdentifier

FieldIdentifier的用途是为对象上的特定属性提供标识。它与System.Reflection.PropertyInfo不同,因为它标识特定对象实例上的属性,而反射标识类上的属性。
给定一个具有名为PostCode的属性的Address类,我们可以预期以下相等规则:

Values Equal?
// Reflection: Same property on difference instances
address1.GetProperty(“PostalCode”);
address2.GetProperty(“PostalCode”);
true
// FieldIdentifier: Same property on same instance
new FieldIdentifier(address1, “PostalCode”);
new FieldIdentifier(address1, “PostalCode”);
true
// FieldIdentifier: Same property on different instances
new FieldIdentifier(address1, “PostalCode”);
new FieldIdentifier(address2, “PostalCode”);
false

当需要将UI状态(如验证错误)绑定到输入值时,我们需要某种方法来识别该状态与哪些输入数据相关。在以前的Web技术中,单个输入通常使用字符串来标识,下面是一些示例:

  • EmailAddress
  • HomeAddress.PostalCode
  • WorkAddress.PostalCode

一旦用户界面变得复杂,这些路径可能会相当复杂。

  • Contacts[0].Name
  • Contacts[0].ContactDetails[0].TelephoneNumber
  • Contacts[0].ContactDetails[0].EmailAddress
  • Contacts[9].ContactDetails[3].TelephoneNumber

Blazor简化了这一过程,因为它的设计方式允许它始终使用同一进程中的对象和属性标识。这为我们提供了通过存储两条简单信息来识别任何对象的任何属性的能力。

  • 对对象本身的直接引用。
  • 该对象上的属性的名称。

标识现在很简单,而且(与字符串路径不同)不必为了考虑数据更改(如从数组中删除项)而进行更改。例如,在字符串路径中,如果要删除列表中的第一个联系人,则需要将Contacts[9].ContactDetails[3].TelephoneNumber更改为Contacts[8].ContactDetails[3].TelephoneNumber。Blazor的ObjectReference/PropertyName方法避免了这种复杂性。
即使我们编写了自己的自定义验证器来与服务器通信以确定有效性(例如,唯一值的可用性,如emailAddress),我们的Blazor验证器也会被赋予一个FieldIdentifier实例,然后服务器调用的结果可以直接与正确对象实例的正确属性相关联。

FieldState

FieldState类包含有关任何对象属性的附加信息。EditContext类有一个类型为Dictionary<FieldIdentifier,FieldState>的私有属性-这允许Blazor将其附加状态存储在展开列表中,以便快速访问。
在给定以下模型的情况下

  1. protected override OnInitialized()
  2. {
  3. var country1 = new Country
  4. {
  5. Code = "GB",
  6. Name = "Great Britain"
  7. };
  8. var address1 = new Address
  9. {
  10. Line1 = "The Mansion",
  11. Line2 = "Bletchley Park",
  12. Line3 = "Sherwood Drive",
  13. Town = "Bletchley",
  14. Area = "Milton Keynes",
  15. PostalCode = "MK3 6EB",
  16. Country = country1
  17. };
  18. var person1 = new Person
  19. {
  20. Name = "My name",
  21. Age = 12,
  22. HomeAddress = address1,
  23. TelephoneNumber = "+44 (0) 1908 64004"
  24. };
  25. }

我们预计会看到如下所示的字段标识符:
image.png

注意:只有在需要时才会将条目添加到词典中。