【发布时间】:2021-08-09 21:09:08
【问题描述】:
我正在尝试了解 Blazor 的内部工作原理(并最终编写一些中间件)。我有一个fiddle,它以三种不同的方式绑定三个不同的字段:
- FirstName 字段绑定到 InputText 按预期工作,并在清除框和焦点更改时显示验证消息。
- MiddleName 字段绑定到常规输入,不能“按预期”工作,并且在清除该字段和焦点更改时不显示任何验证消息。通过 Blazor 源,我发现 EditContext.NotifyFieldChanged 如果控件本身(InputBase)是一个问题。
- 值得注意的是,如果您提交我想了解所涉及的生命周期的表单,则会显示该消息。
- LastName 字段也绑定到常规输入,但需要做一些小技巧来引发 EditContext.OnFieldChanged 并触发验证工作。 有没有更好的方法来为 onchange 做到这一点?提交如何设法引发验证消息? 有很多引用捕获、表达式、反射和使用“仅供内部使用”的 CreateBinder 方法。
下面是小提琴的代码,方便参考:
@page "/"
@using System.ComponentModel.DataAnnotations
@using System.Linq.Expressions;
@using System.Reflection;
@implements IHasEditContext;
<h1>Hello, world!</h1>
<EditForm EditContext="this.EditContextRef">
<DataAnnotationsValidator></DataAnnotationsValidator>
<div class="form-group">
<InputText @bind-Value="@this.FirstName" class="form-control" />
<ValidationMessage For="() => this.FirstName"></ValidationMessage>
</div>
<div class="form-group">
<input @bind-value="@this.MiddleName" class="form-control" />
<ValidationMessage For="() => this.MiddleName"></ValidationMessage>
</div>
<div class="form-group">
<input value="@this.LastName" class="form-control" @onchange="(CreateBinder2(this, () => this.LastName, this.LastName))" />
<ValidationMessage For="() => this.LastName"></ValidationMessage>
</div>
<input type="submit" value="Go" />
</EditForm>
@code {
protected override void OnInitialized()
{
base.OnInitialized();
EditContextRef = new EditContext(this);
}
//BasicFormValidator Form1Validator = new BasicFormValidator();
[Required]
public String FirstName { get; set; } = "delete me and change focus to cause validation";
[Required]
public String MiddleName { get; set; } = "delete me and change focus - no validation";
[Required]
public String LastName { get; set; } = "delete me and change focus - validation but manually calling NotifyFieldChanged";
public EditContext EditContextRef { get; set; }
public static EventCallback<ChangeEventArgs> CreateBinder2(
IHasEditContext receiver,
Expression<Func<string?>> propExpression,
string existingValue,
System.Globalization.CultureInfo? culture = null)
{
var fieldIdentifier = FieldIdentifier.Create(propExpression);
Action<String> valueSetter = (string v) =>
{
PropertyInfo prop = fieldIdentifier.Model.GetType().GetProperty(fieldIdentifier.FieldName, BindingFlags.Public | BindingFlags.Instance);
prop.SetValue(fieldIdentifier.Model, v);
receiver.EditContextRef.NotifyFieldChanged(fieldIdentifier);
};
return EventCallback.Factory.CreateBinder<string>(receiver, valueSetter, existingValue, culture);
}
}
【问题讨论】:
-
这可能会有所帮助...chrissainty.com/…
-
@NeilW 这肯定有助于创建示例。但是,我希望不创建控件而只控制绑定。我仍然希望能够使用现有的控件库,但要操纵它们从模型中获取数据的方式。在 MVC 中,这可以通过 ModelBinderProviders、MetadataProviders 和 ValidatorProviders 来完成,但这里似乎不存在该层。我对我创建的 CreateBinder2 方法没问题,但我正在努力更好地理解提交案例,看看是否可以进行任何改进。
-
在不知道“现有控件”示例的情况下,我认为您的问题没有很好的答案。一般来说,您需要某种形式的包装器组件来将数据连接到您的控件并与 Blazor EditForm/EditContext 基础架构进行接口。入侵它几乎肯定会产生您尚未发现的副作用。
-
@MrCakaShaunCurtis 我将为我在示例中使用的通用 提供答案。 NielW 的示例或多或少至少让我觉得我的解决方案没有我想象的那么老套(或多或少地对editcontext、表达式和通知做同样的事情)。因此,虽然我希望对我的 CreateBinder2 有更直接或更直接的方法,但我可以接受它。但我仍然不明白提交是如何设法引发 NotifyFieldChanged 的。
-
@b_levitt。我在下面添加了一个答案。评论空间不足。
标签: blazor blazor-server-side blazor-webassembly