C# 验证两个组件是否具有相同的值
我已经编写了一个由4个输入字段组成的PIN组件(因为它将在一些地方重复使用)C# 验证两个组件是否具有相同的值,c#,blazor,blazor-server-side,C#,Blazor,Blazor Server Side,我已经编写了一个由4个输入字段组成的PIN组件(因为它将在一些地方重复使用) @代码{ [参数] 公共事件回调已完成{get;set;} 私人字符串_pinOne; 私有字符串_pinTwo; 私有字符串_pinThree; 私有字符串_pinFour; 私有作废完成(ChangeEventArgs e) { _pinFour=e.Value.ToString(); 已完成。调用同步(\u pinOne+\u pinTwo+\u pinThree+\u pinFour); } } 然后我创建
@代码{
[参数]
公共事件回调已完成{get;set;}
私人字符串_pinOne;
私有字符串_pinTwo;
私有字符串_pinThree;
私有字符串_pinFour;
私有作废完成(ChangeEventArgs e)
{
_pinFour=e.Value.ToString();
已完成。调用同步(\u pinOne+\u pinTwo+\u pinThree+\u pinFour);
}
}
然后我创建了另一个组件,它使用了其中的两个引脚输入组件
<PinComponent Completed="@PinCompleted"></PinComponent>
<PinComponent Completed="@ConfirmationPinCompleted"></PinComponent>
@code {
private string _pin;
private string _confirmationPin;
private bool _valid = false;
private void PinCompleted(string pin)
{
_pin = pin;
}
private void ConfirmationPinCompleted(string pin)
{
_confirmationPin = pin;
if (_pin.Equals(_confirmationPin))
{
_valid = true;
}
}
}
@代码{
私人字符串(u pin),;
私有字符串_确认PIN;
private bool\u valid=false;
已完成专用无效pin(字符串pin)
{
_引脚=引脚;
}
私人作废确认完成(字符串pin)
{
_确认pin=pin;
如果(_pin.等于(_confirmationPin))
{
_有效=真;
}
}
}
是否可以使用Blazor的ValidationMessage来确保这两个组件共享相同的值 将验证值和结果传递给您的
PinComponent
,并使该组件显示验证错误
<PinComponent Completed="@PinCompleted"></PinComponent>
<PinComponent Completed="@ConfirmationPinCompleted" ValidationMessage="@validationMessage"></PinComponent>
@code {
private string _pin;
private string _confirmationPin;
private bool _valid = false;
private string ValidationMessage => _valid ? string.Empty : "PIN does not match";
private void PinCompleted(string pin)
{
_pin = pin;
}
private void ConfirmationPinCompleted(string pin)
{
_confirmationPin = pin;
if (_pin.Equals(_confirmationPin))
{
_valid = true;
}
}
}
并将值作为模型传递
<EditForm Model="@Model">
<PinComponent Value="@Pin"></PinComponent>
<PinComponent Value="@ConfirmationPin"></PinComponent>
</EditForm>
最后一种方法还没有完全完成,但应该可以让您了解方向。好的,我决定使用FluentValidation,因为出于某种原因,我无法使用自定义属性(或内置的
比较
属性)
剃须刀
<input class="pinBox" type="password" maxlength="1" size="1" onkeypress='return event.charCode >= 48 && event.charCode <= 57' required @bind="@_pinOne"/>
<input class="pinBox" type="password" maxlength="1" size="1" onkeypress='return event.charCode >= 48 && event.charCode <= 57' required @bind="@_pinTwo"/>
<input class="pinBox" type="password" maxlength="1" size="1" onkeypress='return event.charCode >= 48 && event.charCode <= 57' required @bind="@_pinThree"/>
<input class="pinBox" type="password" maxlength="1" size="1" onkeypress='return event.charCode >= 48 && event.charCode <= 57' required @bind="@_pinFour" @oninput="Completion"/>
@code{
private string _value;
[Parameter]
public string Value
{
get { return Value; }
set
{
if (string.IsNullOrWhiteSpace(value))
{
_pinOne = null;
_pinTwo = null;
_pinThree = null;
_pinFour = null;
}
_value = value;
}
}
[Parameter]
public EventCallback<string> ValueChanged { get; set; }
private string _pinOne;
private string _pinTwo;
private string _pinThree;
private string _pinFour;
private void Completion(ChangeEventArgs e)
{
_pinFour = e.Value.ToString();
ValueChanged.InvokeAsync(_pinOne + _pinTwo + _pinThree + _pinFour);
}
}
@using Application.Validation
<EditForm Model="@_model" OnValidSubmit="@OnValidSubmit" OnInvalidSubmit="@OnInvalidSubmit">
<div class="pinContainer">
<PinComponent @bind-Value="_model.Pin"></PinComponent>
<PinComponent @bind-Value="_model.PinConfirmation"></PinComponent>
</div>
<FluentValidationValidator />
<ValidationSummary />
<input id="btnSubmit" class="btn btnFont" type="submit" value="Register PIN" style="margin-top: 5px;" />
</EditForm>
@code {
private PinModel _model = new PinModel();
void OnValidSubmit()
{
}
void OnInvalidSubmit()
{
_model.Pin = null;
_model.PinConfirmation = null;
StateHasChanged();
}
}
下面我使用了FluentValidation
EditContextFluentValidationExtensions.cs
public static class EditContextFluentValidationExtensions
{
public static EditContext AddFluentValidation(this EditContext editContext)
{
if (editContext == null)
{
throw new ArgumentNullException(nameof(editContext));
}
var messages = new ValidationMessageStore(editContext);
editContext.OnValidationRequested +=
(sender, eventArgs) => ValidateModel((EditContext)sender, messages);
editContext.OnFieldChanged +=
(sender, eventArgs) => ValidateField(editContext, messages, eventArgs.FieldIdentifier);
return editContext;
}
private static void ValidateModel(EditContext editContext, ValidationMessageStore messages)
{
var validator = GetValidatorForModel(editContext.Model);
if (validator == null)
return;
var validationResults = validator.Validate(editContext.Model);
messages.Clear();
foreach (var validationResult in validationResults.Errors)
{
messages.Add(editContext.Field(validationResult.PropertyName), validationResult.ErrorMessage);
}
editContext.NotifyValidationStateChanged();
}
private static void ValidateField(EditContext editContext, ValidationMessageStore messages, in FieldIdentifier fieldIdentifier)
{
var properties = new[] { fieldIdentifier.FieldName };
var context = new ValidationContext(fieldIdentifier.Model, new PropertyChain(), new MemberNameValidatorSelector(properties));
var validator = GetValidatorForModel(fieldIdentifier.Model);
if (validator == null)
return;
var validationResults = validator.Validate(context);
messages.Clear(fieldIdentifier);
foreach (var validationResult in validationResults.Errors)
{
messages.Add(editContext.Field(validationResult.PropertyName), validationResult.ErrorMessage);
}
editContext.NotifyValidationStateChanged();
}
private static IValidator GetValidatorForModel(object model)
{
var abstractValidatorType = typeof(AbstractValidator<>).MakeGenericType(model.GetType());
var modelValidatorType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t => t.IsSubclassOf(abstractValidatorType));
if (modelValidatorType == null)
return null;
var modelValidatorInstance = (IValidator)Activator.CreateInstance(modelValidatorType);
return modelValidatorInstance;
}
}
PinValidator.cs
public class FluentValidationValidator : ComponentBase
{
[CascadingParameter]
EditContext CurrentEditContext { get; set; }
protected override void OnInitialized()
{
if (CurrentEditContext == null)
{
throw new InvalidOperationException($"{nameof(FluentValidationValidator)} requires a cascading " +
$"parameter of type {nameof(EditContext)}. For example, you can use {nameof(FluentValidationValidator)} " +
$"inside an {nameof(EditForm)}.");
}
CurrentEditContext.AddFluentValidation();
}
}
public class PinValidator : AbstractValidator<PinModel>
{
public PinValidator()
{
RuleFor(p => p.Pin).NotNull().Matches("^[0-9]{4}$");
RuleFor(p => p).Must(PinsAreSame)
.WithMessage("PINs must be the same");
}
private bool PinsAreSame(PinModel pinModel)
{
return (pinModel.Pin.Equals(pinModel.PinConfirmation));
}
}
公共类PinValidator:AbstractValidator
{
公共验证程序()
{
RuleFor(p=>p.Pin).NotNull()匹配(“^[0-9]{4}$”;
规则(p=>p).Must(PinsAreSame)
.WithMessage(“PIN必须相同”);
}
私人bool PinsAreSame(PinModel PinModel)
{
返回(pinModel.Pin.Equals(pinModel.PinConfirmation));
}
}
谢谢,您能帮助/详细说明一下如何使用模型吗?我尝试过这种方法,但似乎无法让它工作(我刚刚在组件中将PinModel作为私有字段,将EditForm的模型设置为它,然后更新了我的PinCompleted和ConfirmationPinCompleted方法中的属性)
public static class EditContextFluentValidationExtensions
{
public static EditContext AddFluentValidation(this EditContext editContext)
{
if (editContext == null)
{
throw new ArgumentNullException(nameof(editContext));
}
var messages = new ValidationMessageStore(editContext);
editContext.OnValidationRequested +=
(sender, eventArgs) => ValidateModel((EditContext)sender, messages);
editContext.OnFieldChanged +=
(sender, eventArgs) => ValidateField(editContext, messages, eventArgs.FieldIdentifier);
return editContext;
}
private static void ValidateModel(EditContext editContext, ValidationMessageStore messages)
{
var validator = GetValidatorForModel(editContext.Model);
if (validator == null)
return;
var validationResults = validator.Validate(editContext.Model);
messages.Clear();
foreach (var validationResult in validationResults.Errors)
{
messages.Add(editContext.Field(validationResult.PropertyName), validationResult.ErrorMessage);
}
editContext.NotifyValidationStateChanged();
}
private static void ValidateField(EditContext editContext, ValidationMessageStore messages, in FieldIdentifier fieldIdentifier)
{
var properties = new[] { fieldIdentifier.FieldName };
var context = new ValidationContext(fieldIdentifier.Model, new PropertyChain(), new MemberNameValidatorSelector(properties));
var validator = GetValidatorForModel(fieldIdentifier.Model);
if (validator == null)
return;
var validationResults = validator.Validate(context);
messages.Clear(fieldIdentifier);
foreach (var validationResult in validationResults.Errors)
{
messages.Add(editContext.Field(validationResult.PropertyName), validationResult.ErrorMessage);
}
editContext.NotifyValidationStateChanged();
}
private static IValidator GetValidatorForModel(object model)
{
var abstractValidatorType = typeof(AbstractValidator<>).MakeGenericType(model.GetType());
var modelValidatorType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t => t.IsSubclassOf(abstractValidatorType));
if (modelValidatorType == null)
return null;
var modelValidatorInstance = (IValidator)Activator.CreateInstance(modelValidatorType);
return modelValidatorInstance;
}
}
public class FluentValidationValidator : ComponentBase
{
[CascadingParameter]
EditContext CurrentEditContext { get; set; }
protected override void OnInitialized()
{
if (CurrentEditContext == null)
{
throw new InvalidOperationException($"{nameof(FluentValidationValidator)} requires a cascading " +
$"parameter of type {nameof(EditContext)}. For example, you can use {nameof(FluentValidationValidator)} " +
$"inside an {nameof(EditForm)}.");
}
CurrentEditContext.AddFluentValidation();
}
}
public class PinValidator : AbstractValidator<PinModel>
{
public PinValidator()
{
RuleFor(p => p.Pin).NotNull().Matches("^[0-9]{4}$");
RuleFor(p => p).Must(PinsAreSame)
.WithMessage("PINs must be the same");
}
private bool PinsAreSame(PinModel pinModel)
{
return (pinModel.Pin.Equals(pinModel.PinConfirmation));
}
}