From 07ec52bf4d1eb9a635264c36b66d21f00e3e42c2 Mon Sep 17 00:00:00 2001 From: maomao_zhen Date: Thu, 26 Sep 2024 14:58:30 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20MetadataType=20?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=E7=BB=A7=E6=89=BF=20IValidateCollection=20?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E9=AA=8C=E8=AF=81=E5=90=8E=E5=8F=88=E5=AF=B9?= =?UTF-8?q?=E5=85=B6=E4=B8=AD=E6=B6=89=E5=8F=8A=E7=9A=84=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E4=BA=86=E5=8D=95=E7=8B=AC=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=EF=BC=8C=E5=9C=A8=E7=89=B9=E5=AE=9A=E6=83=85=E5=86=B5=E4=B8=8B?= =?UTF-8?q?=E4=BC=9A=E5=BF=BD=E7=95=A5=E5=8D=95=E7=8B=AC=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E7=9A=84=E9=94=99=E8=AF=AF=E6=8F=90=E7=A4=BA=E3=80=82#4359?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/ValidateForm/ValidateForm.razor.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs index 257fb7ba4e8..3ad3563eabb 100644 --- a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs +++ b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs @@ -426,6 +426,8 @@ private void ValidateDataAnnotations(object? value, ValidationContext context, L ? rule.FormatErrorMessage(displayName) : rule.ErrorMessage; results.Add(new ValidationResult(errorMessage, new string[] { memberName })); + //从验证通过的字段集合中移除后续验证错误的字段名称。 + ValidMemberNames.Remove(memberName); } } } @@ -508,7 +510,16 @@ private async Task ValidateAsync(IValidateComponent validator, ValidationContext { // 自定义验证组件 _tcs = new(); + //记录验证前的错误字段名集合。 + var oldNames = messages.SelectMany(x => x.MemberNames).ToList(); await validator.ValidatePropertyAsync(propertyValue, context, messages); + //验证后的错误字段名集合。 + var newNames = messages.SelectMany(x => x.MemberNames).ToList(); + //计算新增的验证错误字段名称集合。 + var removeNames = newNames.Where(x => oldNames.Contains(x)).ToArray(); + //从验证通过的字段集合内移除后续验证错误的字段名。 + foreach (var name in removeNames) + ValidMemberNames.Remove(name); _tcs.TrySetResult(messages.Count == 0); } From 7e26f4235c2a41aff87cb08e1355cc16d9defb2b Mon Sep 17 00:00:00 2001 From: Argo Date: Thu, 26 Sep 2024 15:42:43 +0800 Subject: [PATCH 2/9] =?UTF-8?q?fix:=20=E6=9B=B4=E6=96=B0=20ValidateForm=20?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ValidateForm/ValidateForm.razor.cs | 98 +++++++++++-------- 1 file changed, 58 insertions(+), 40 deletions(-) diff --git a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs index 257fb7ba4e8..2f174a893fd 100644 --- a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs +++ b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs @@ -21,7 +21,6 @@ public partial class ValidateForm /// is determined to be valid. /// [Parameter] - [NotNull] public Func? OnValidSubmit { get; set; } /// @@ -29,7 +28,6 @@ public partial class ValidateForm /// is determined to be invalid. /// [Parameter] - [NotNull] public Func? OnInvalidSubmit { get; set; } /// @@ -107,6 +105,11 @@ public partial class ValidateForm /// private readonly ConcurrentDictionary<(string FieldName, Type ModelType), (FieldIdentifier FieldIdentifier, IValidateComponent ValidateComponent)> _validatorCache = new(); + /// + /// 验证组件验证结果缓存 + /// + private readonly ConcurrentDictionary> _validateResults = new(); + private string? DisableAutoSubmitString => (DisableAutoSubmitFormByEnter.HasValue && DisableAutoSubmitFormByEnter.Value) ? "true" : null; /// @@ -165,7 +168,7 @@ internal void AddValidator((string FieldName, Type ModelType) key, (FieldIdentif /// /// /// - internal bool TryRemoveValidator((string FieldName, Type ModelType) key, [MaybeNullWhen(false)] out (FieldIdentifier FieldIdentifier, IValidateComponent IValidateComponent) value) => _validatorCache.TryRemove(key, out value); + internal bool TryRemoveValidator((string FieldName, Type ModelType) key, out (FieldIdentifier FieldIdentifier, IValidateComponent IValidateComponent) value) => _validatorCache.TryRemove(key, out value); /// /// 设置指定字段错误信息 @@ -187,19 +190,23 @@ public void SetError(Expression> expression, strin private void InternalSetError(MemberExpression exp, string errorMessage) { var fieldName = exp.Member.Name; - if (exp.Expression != null) + if (exp.Expression == null) { - var modelType = exp.Expression.Type; - var validator = _validatorCache.FirstOrDefault(c => c.Key.ModelType == modelType && c.Key.FieldName == fieldName).Value.ValidateComponent; - if (validator != null) - { - var results = new List - { - new(errorMessage, new string[] { fieldName }) - }; - validator.ToggleMessage(results); - } + return; } + + var modelType = exp.Expression.Type; + var validator = _validatorCache.FirstOrDefault(c => c.Key.ModelType == modelType && c.Key.FieldName == fieldName).Value.ValidateComponent; + if (validator == null) + { + return; + } + + var results = new List + { + new(errorMessage, [fieldName]) + }; + validator.ToggleMessage(results); } /// @@ -213,7 +220,7 @@ public void SetError(string propertyName, string errorMessage) { var results = new List { - new(errorMessage, new string[] { fieldName }) + new(errorMessage, [fieldName]) }; validator.ToggleMessage(results); } @@ -241,7 +248,7 @@ private bool TryGetModelField(string propertyName, [MaybeNullWhen(false)] out Ty return propNames.IsEmpty; } - private bool TryGetValidator(Type modelType, string fieldName, [NotNullWhen(true)] out IValidateComponent validator) + private bool TryGetValidator(Type modelType, string fieldName, out IValidateComponent validator) { validator = _validatorCache.FirstOrDefault(c => c.Key.ModelType == modelType && c.Key.FieldName == fieldName).Value.ValidateComponent; return validator != null; @@ -256,6 +263,8 @@ private bool TryGetValidator(Type modelType, string fieldName, [NotNullWhen(true /// internal async Task ValidateObject(ValidationContext context, List results) { + _validateResults.Clear(); + if (ValidateAllProperties) { await ValidateProperty(context, results); @@ -266,30 +275,29 @@ internal async Task ValidateObject(ValidationContext context, List(); - var pi = key.ModelType.GetPropertyByName(key.FieldName); - if (pi != null) + continue; + } + + var messages = new List(); + var pi = key.ModelType.GetPropertyByName(key.FieldName); + if (pi != null) + { + var propertyValidateContext = new ValidationContext(fieldIdentifier.Model, context, null) { - var propertyValidateContext = new ValidationContext(fieldIdentifier.Model, context, null) - { - MemberName = fieldIdentifier.FieldName, - DisplayName = fieldIdentifier.GetDisplayName() - }; + MemberName = fieldIdentifier.FieldName, + DisplayName = fieldIdentifier.GetDisplayName() + }; - // 设置其关联属性字段 - var propertyValue = Utility.GetPropertyValue(fieldIdentifier.Model, fieldIdentifier.FieldName); + // 设置其关联属性字段 + var propertyValue = Utility.GetPropertyValue(fieldIdentifier.Model, fieldIdentifier.FieldName); - await ValidateAsync(validator, propertyValidateContext, messages, pi, propertyValue); - } - // 客户端提示 - validator.ToggleMessage(messages); - results.AddRange(messages); + await ValidateAsync(validator, propertyValidateContext, messages, pi, propertyValue); } + _validateResults.TryAdd(validator, messages); + results.AddRange(messages); } // 验证 IValidatableObject @@ -306,8 +314,8 @@ internal async Task ValidateObject(ValidationContext context, List 0) { foreach (var key in _validatorCache.Keys) { @@ -315,13 +323,23 @@ internal async Task ValidateObject(ValidationContext context, List messages, (k, m) => + { + m.AddRange(messages); + return m; + }); } } results.AddRange(messages); } } } + + ValidMemberNames.RemoveAll(name => _validateResults.Values.SelectMany(i => i).Any(i => i.MemberNames.Contains(name))); + foreach (var (validator, messages) in _validateResults) + { + validator.ToggleMessage(messages); + } } } @@ -425,7 +443,7 @@ private void ValidateDataAnnotations(object? value, ValidationContext context, L var errorMessage = !string.IsNullOrEmpty(rule.ErrorMessage) && rule.ErrorMessage.Contains("{0}") ? rule.FormatErrorMessage(displayName) : rule.ErrorMessage; - results.Add(new ValidationResult(errorMessage, new string[] { memberName })); + results.Add(new ValidationResult(errorMessage, [memberName])); } } } @@ -507,7 +525,7 @@ private async Task ValidateAsync(IValidateComponent validator, ValidationContext if (messages.Count == 0) { // 自定义验证组件 - _tcs = new(); + _tcs = new TaskCompletionSource(); await validator.ValidatePropertyAsync(propertyValue, context, messages); _tcs.TrySetResult(messages.Count == 0); } From 32a25e52e79c7c8ba5bdc38df9ed67ac9ecbfc77 Mon Sep 17 00:00:00 2001 From: Argo-AscioTech Date: Thu, 26 Sep 2024 15:47:43 +0800 Subject: [PATCH 3/9] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ValidateForm/ValidateForm.razor.cs | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs index 2f174a893fd..f76bd684566 100644 --- a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs +++ b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs @@ -189,24 +189,22 @@ public void SetError(Expression> expression, strin private void InternalSetError(MemberExpression exp, string errorMessage) { - var fieldName = exp.Member.Name; - if (exp.Expression == null) + if (exp.Expression != null) { - return; - } + var fieldName = exp.Member.Name; + var modelType = exp.Expression.Type; + var validator = _validatorCache.FirstOrDefault(c => c.Key.ModelType == modelType && c.Key.FieldName == fieldName).Value.ValidateComponent; + if (validator == null) + { + return; + } - var modelType = exp.Expression.Type; - var validator = _validatorCache.FirstOrDefault(c => c.Key.ModelType == modelType && c.Key.FieldName == fieldName).Value.ValidateComponent; - if (validator == null) - { - return; + var results = new List + { + new(errorMessage, [fieldName]) + }; + validator.ToggleMessage(results); } - - var results = new List - { - new(errorMessage, [fieldName]) - }; - validator.ToggleMessage(results); } /// From f29c2377b35723221029d222313cf68dc0bc4a7c Mon Sep 17 00:00:00 2001 From: Argo-AscioTech Date: Thu, 26 Sep 2024 16:05:39 +0800 Subject: [PATCH 4/9] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=94=B9=20IValidateC?= =?UTF-8?q?ollection=20=E6=8E=A5=E5=8F=A3=E6=96=B9=E6=B3=95=E5=90=8D?= =?UTF-8?q?=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/ValidateForms.razor.cs | 6 +++--- .../Data/CustomValidateCollectionModel.cs | 4 ++-- .../Components/Validate/IValidateCollection.cs | 4 ++-- .../Components/ValidateForm/ValidateForm.razor.cs | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/ValidateForms.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/ValidateForms.razor.cs index 9ce3cf4d4fb..8a87539124f 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/ValidateForms.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/ValidateForms.razor.cs @@ -163,12 +163,12 @@ public IEnumerable Validate(ValidationContext validationContex _validMemberNames.AddRange([nameof(model.Email), nameof(model.ConfirmEmail)]); } } - return InvalidMemberNames(); + return GetInvalidMemberNames(); } - public List ValidMemberNames() => _validMemberNames; + public List GetValidMemberNames() => _validMemberNames; - public List InvalidMemberNames() => _invalidMemberNames; + public List GetInvalidMemberNames() => _invalidMemberNames; } class ComplexFoo : Foo diff --git a/src/BootstrapBlazor.Server/Data/CustomValidateCollectionModel.cs b/src/BootstrapBlazor.Server/Data/CustomValidateCollectionModel.cs index 54404435972..a757a0c7ec7 100644 --- a/src/BootstrapBlazor.Server/Data/CustomValidateCollectionModel.cs +++ b/src/BootstrapBlazor.Server/Data/CustomValidateCollectionModel.cs @@ -61,11 +61,11 @@ public IEnumerable Validate(ValidationContext validationContex /// /// /// - public List ValidMemberNames() => _validMemberNames; + public List GetValidMemberNames() => _validMemberNames; /// /// /// /// - public List InvalidMemberNames() => _invalidMemberNames; + public List GetInvalidMemberNames() => _invalidMemberNames; } diff --git a/src/BootstrapBlazor/Components/Validate/IValidateCollection.cs b/src/BootstrapBlazor/Components/Validate/IValidateCollection.cs index 2f5f3c8244e..e500017b51a 100644 --- a/src/BootstrapBlazor/Components/Validate/IValidateCollection.cs +++ b/src/BootstrapBlazor/Components/Validate/IValidateCollection.cs @@ -20,11 +20,11 @@ public interface IValidateCollection /// 返回合法成员集合 /// /// - List ValidMemberNames(); + List GetValidMemberNames(); /// /// 返回非法成员集合 /// /// - List InvalidMemberNames(); + List GetInvalidMemberNames(); } diff --git a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs index f76bd684566..a55063a45ec 100644 --- a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs +++ b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs @@ -543,8 +543,8 @@ private async Task ValidateAsync(IValidateComponent validator, ValidationContext if (validate != null) { messages.AddRange(validate.Validate(context)); - ValidMemberNames.AddRange(validate.ValidMemberNames()); - InvalidMemberNames.AddRange(validate.InvalidMemberNames()); + ValidMemberNames.AddRange(validate.GetValidMemberNames()); + InvalidMemberNames.AddRange(validate.GetInvalidMemberNames()); } } } From 65e9d64278f7089f4cce29cb8fdc737ab3e8c678 Mon Sep 17 00:00:00 2001 From: maomao_zhen Date: Thu, 26 Sep 2024 16:40:14 +0800 Subject: [PATCH 5/9] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E4=BB=A5=E9=80=9A=E8=BF=87=E9=AA=8C=E8=AF=81=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/ValidateForm/ValidateForm.razor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs index 3ad3563eabb..c6d1ec502e2 100644 --- a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs +++ b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs @@ -516,10 +516,10 @@ private async Task ValidateAsync(IValidateComponent validator, ValidationContext //验证后的错误字段名集合。 var newNames = messages.SelectMany(x => x.MemberNames).ToList(); //计算新增的验证错误字段名称集合。 - var removeNames = newNames.Where(x => oldNames.Contains(x)).ToArray(); + var removeNames = newNames.Where(x => oldNames.Contains(x)).ToList(); //从验证通过的字段集合内移除后续验证错误的字段名。 - foreach (var name in removeNames) - ValidMemberNames.Remove(name); + ValidMemberNames.RemoveAll(x => removeNames.Contains(x)); + _tcs.TrySetResult(messages.Count == 0); } From d4c9cd84842c2033fb1cd8ff510f10b3c6cd8df5 Mon Sep 17 00:00:00 2001 From: Argo-AscioTech Date: Thu, 26 Sep 2024 19:51:52 +0800 Subject: [PATCH 6/9] =?UTF-8?q?doc:=20=E5=A2=9E=E5=8A=A0=E6=B3=A8=E9=87=8A?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Validate/ValidateBase.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BootstrapBlazor/Components/Validate/ValidateBase.cs b/src/BootstrapBlazor/Components/Validate/ValidateBase.cs index 880818b8100..704b384ab63 100644 --- a/src/BootstrapBlazor/Components/Validate/ValidateBase.cs +++ b/src/BootstrapBlazor/Components/Validate/ValidateBase.cs @@ -301,6 +301,7 @@ protected override void OnParametersSet() if (ValidateForm != null) { + // IValidateCollection 支持组件间联动验证 var fieldName = FieldIdentifier?.FieldName; if (!string.IsNullOrEmpty(fieldName)) { From 97b8a281ee6e06ec3960a2baf43a5e916ab2a5c0 Mon Sep 17 00:00:00 2001 From: Argo-AscioTech Date: Thu, 26 Sep 2024 19:52:01 +0800 Subject: [PATCH 7/9] =?UTF-8?q?refactor:=20=E7=B2=BE=E7=AE=80=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/ValidateForm/ValidateForm.razor.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs index a55063a45ec..591331500ba 100644 --- a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs +++ b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs @@ -321,11 +321,7 @@ internal async Task ValidateObject(ValidationContext context, List messages, (k, m) => - { - m.AddRange(messages); - return m; - }); + _validateResults[validator].AddRange(messages); } } results.AddRange(messages); From 5a815427bf1eff7888e7aa8083dfd4a31789f0f5 Mon Sep 17 00:00:00 2001 From: Argo-AscioTech Date: Thu, 26 Sep 2024 22:47:49 +0800 Subject: [PATCH 8/9] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/ValidateFormTest.cs | 101 ++++++++++++++++++- 1 file changed, 97 insertions(+), 4 deletions(-) diff --git a/test/UnitTest/Components/ValidateFormTest.cs b/test/UnitTest/Components/ValidateFormTest.cs index e67b8e627de..05b66440c37 100644 --- a/test/UnitTest/Components/ValidateFormTest.cs +++ b/test/UnitTest/Components/ValidateFormTest.cs @@ -261,6 +261,43 @@ public void MetadataTypeIValidatableObject_Ok() Assert.Equal("两次密码必须一致。", message); } + [Fact] + public async Task MetadataTypeIValidateCollection_Ok() + { + var model = new Dummy2() { Value1 = 0, Value2 = 0 }; + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.Model, model); + pb.AddChildContent>(pb => + { + pb.Add(a => a.Value, model.Value1); + pb.Add(a => a.ValueExpression, Utility.GenerateValueExpression(model, "Value1", typeof(int))); + }); + pb.AddChildContent>(pb => + { + pb.Add(a => a.Value, model.Value2); + pb.Add(a => a.ValueExpression, Utility.GenerateValueExpression(model, "Value2", typeof(int))); + }); + }); + var form = cut.Find("form"); + await cut.InvokeAsync(() => form.Submit()); + var input = cut.FindComponent>(); + var all = cut.FindComponents>(); + var input2 = all[all.Count - 1]; + Assert.Null(input.Instance.GetErrorMessage()); + Assert.Equal("Value2 必须大于 0", input2.Instance.GetErrorMessage()); + + model.Value1 = 0; + model.Value2 = 2; + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.Model, model); + }); + await cut.InvokeAsync(() => form.Submit()); + Assert.Equal("Value1 必须大于 Value2", input.Instance.GetErrorMessage()); + Assert.Equal("Value1 必须大于 Value2", input2.Instance.GetErrorMessage()); + } + [Fact] public void Validate_Class_Ok() { @@ -698,6 +735,7 @@ private class Dummy public string? File { get; set; } public string? Password1 { get; set; } + public string? Password2 { get; set; } } @@ -712,13 +750,68 @@ public IEnumerable Validate(ValidationContext validationContex if (validationContext.ObjectInstance is Dummy dy) { if (!string.Equals(dy.Password1, dy.Password2, StringComparison.InvariantCultureIgnoreCase)) - result.Add(new ValidationResult("两次密码必须一致。", - [nameof(Dummy.Password1), nameof(Dummy.Password2)])); + { + result.Add(new ValidationResult("两次密码必须一致。", [nameof(Dummy.Password1), nameof(Dummy.Password2)])); + } } return result; } } + [MetadataType(typeof(Dummy2MetadataCollection))] + private class Dummy2 + { + public int Value1 { get; set; } + + public int Value2 { get; set; } + } + + public class Dummy2MetadataCollection : IValidateCollection + { + [Required] + public int Value1 { get; set; } + + [CustomValidation(typeof(Dummy2MetadataCollection), nameof(CustomValidate), ErrorMessage = "{0} 必须大于 0")] + [Required] + public int Value2 { get; set; } + + private readonly List _validMemberNames = []; + + public List GetValidMemberNames() => _validMemberNames; + + private readonly List _invalidMemberNames = []; + + public List GetInvalidMemberNames() => _invalidMemberNames; + + public IEnumerable Validate(ValidationContext validationContext) + { + _invalidMemberNames.Clear(); + _validMemberNames.Clear(); + if (validationContext.ObjectInstance is Dummy2 dummy) + { + if (dummy.Value1 < dummy.Value2) + { + _invalidMemberNames.Add(new ValidationResult("Value1 必须大于 Value2", [nameof(Dummy2.Value1), nameof(Dummy2.Value2)])); + } + else + { + _validMemberNames.AddRange([nameof(Dummy2.Value1), nameof(Dummy2.Value2)]); + } + } + return _invalidMemberNames; + } + + public static ValidationResult? CustomValidate(object value, ValidationContext context) + { + ValidationResult? ret = null; + if (value is int v && v < 1) + { + ret = new ValidationResult("Value2 必须大于 0", ["Value2"]); + } + return ret; + } + } + private class MockFoo { [Required(ErrorMessage = "{0} is Required")] @@ -803,13 +896,13 @@ public IEnumerable Validate(ValidationContext validationContex /// /// /// - public List ValidMemberNames() => _validMemberNames; + public List GetValidMemberNames() => _validMemberNames; /// /// /// /// - public List InvalidMemberNames() => _invalidMemberNames; + public List GetInvalidMemberNames() => _invalidMemberNames; } private class MockInput : BootstrapInput From c5cadadb8c1d4691a34945f52069e3cf2a34c396 Mon Sep 17 00:00:00 2001 From: Argo-AscioTech Date: Thu, 26 Sep 2024 22:52:58 +0800 Subject: [PATCH 9/9] chore: bump version 8.9.4-beta06 --- src/BootstrapBlazor/BootstrapBlazor.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index 54484625175..e0161cf7d29 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,7 +1,7 @@ - 8.9.4-beta05 + 8.9.4-beta06