C# 验证两个组件是否具有相同的值

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); } } 然后我创建

我已经编写了一个由4个输入字段组成的PIN组件(因为它将在一些地方重复使用)


@代码{
[参数]
公共事件回调已完成{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));
        }
    }