したいこと
- カスタム検証(融点(Melting point)<=沸点(Boiling point))を定義したクラスがあり、この入力フォームを作成しています。
- このクラスの入力フォームを作ったときMelting point入力→Boiling pointとするとMelting pointの検証エラーが消えません。
- Boiling point入力時にMelting pointの再検証を行うにはどうすればよいでしょうか?
- ASP.NET MVCだと「TryValidateModel」というのがあるようなのですが、BlazorのRazorコンポーネントでは@modelは使えそうにありません。
- 参考URL:ASP.NET Core MVC および Razor Pages でのモデルの検証 - 検証を再実行する
- MudBlazorを利用した状態でのコードが知りたいところではありますが、標準のEditFormならこうする、という情報でも頂けるとありがたいです。
開発環境
- Visual Studio 2022
- .NET 6.0 (※LTSなので使っているだけなので、7.0ならこう解決できる、というのがあれば教えて欲しいと思っています)
- Blazor Server
- 利用コンポーネント ライブラリ:MudBlazor
ソースコード
C#
1 public class Element 2 { 3 [Required(ErrorMessage = "Name is required")] 4 public string Name { get; set; } = ""; 5 6 [Required(ErrorMessage = "Melting point is required")] 7 [CheckMeltByBoil(ErrorMessage = "Boiling point must be higher than melting point.")] 8 public double MeltingPoint { get; set; } = 0.0; 9 10 [Required(ErrorMessage = "Boiling point is required")] 11 [CheckBoilByMelt(ErrorMessage = "Boiling point must be higher than melting point.")] 12 public double BoilingPoint { get; set; } = 0.0; 13 } 14 //サンプル:new Element { Name = "Hydrogen", MeltingPoint = -259.14, BoilingPoint = -252.87 }, 15 16 [AttributeUsage(AttributeTargets.Property)] 17 public class CheckMeltByBoilAttribute : ValidationAttribute 18 { 19 protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) 20 { 21 var model = validationContext.ObjectInstance as Element; 22 if (model is null || value is null) 23 { 24 throw new NullReferenceException(); 25 } 26 27 if ((double)value <= model.BoilingPoint) 28 { 29 return ValidationResult.Success; 30 } 31 else 32 { 33 return new ValidationResult(null); 34 } 35 } 36 } 37 38 [AttributeUsage(AttributeTargets.Property)] 39 public class CheckBoilByMeltAttribute : ValidationAttribute 40 { 41 protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) 42 { 43 var model = validationContext.ObjectInstance as Element; 44 if (model is null || value is null) 45 { 46 throw new NullReferenceException(); 47 } 48 49 if (model.MeltingPoint <= (double)value) 50 { 51 return ValidationResult.Success; 52 } 53 else 54 { 55 return new ValidationResult(null); 56 } 57 } 58 }
Razor
1@using System.Globalization 2@using MudDataGridSample.Data 3 4<MudDialog> 5 <TitleContent> 6 <MudText Typo="Typo.h6"> 7 @(IsEdit ? "Edit" : "Create") 8 </MudText> 9 </TitleContent> 10 <DialogContent> 11 <MudForm @ref="form" @bind-IsValid="@success"> 12 <MudStack Spacing="1"> 13 <MudTextField Label="Name" HelperText="(HelperText)" @bind-Value="EditData.Name" For="@(() => EditData.Name)" /> 14 <MudNumericField Label="MeltingPoint" HelperText="(HelperText)" Format="N4" Culture="@CultureInfo.GetCultureInfo("en-US")" T="double" @bind-Value="EditData.MeltingPoint" For="@(() => EditData.MeltingPoint)" TextChanged="(string _val) => OnValueChangeHandler1(_val)" /> 15 <MudNumericField Label="BoilingPoint" HelperText="(HelperText)" Format="N4" Culture="@CultureInfo.GetCultureInfo("en-US")" T="double" @bind-Value="EditData.BoilingPoint" For="@(() => EditData.BoilingPoint)" TextChanged="(string _val) => OnValueChangeHandler2(_val)" /> 16 </MudStack> 17 </MudForm> 18 </DialogContent> 19 <DialogActions> 20 <MudButton OnClick="Cancel">Cancel</MudButton> 21 <MudButton Color="Color.Primary" Disabled="@(!success)" OnClick="Submit">Ok</MudButton> 22 </DialogActions> 23</MudDialog> 24 25@code { 26 bool success = false; 27 MudForm? form; 28 29 [CascadingParameter] MudDialogInstance? MudDialog { get; set; } 30 31 [Parameter] public bool IsEdit { get; set; } = false; 32 [Parameter] public Element EditData { get; set; } = new(); 33 34 35 protected async Task OnValueChangeHandler1(string newValue) 36 { 37 double set_val = 0.0; 38 if (!double.TryParse(newValue, out set_val)) 39 { 40 return; 41 } 42 43 //入れ直してStateHasChangedしても効果無し 44 EditData.MeltingPoint = set_val; 45 double tmp = EditData.BoilingPoint; 46 EditData.BoilingPoint = EditData.BoilingPoint + 1.0; 47 await InvokeAsync(StateHasChanged); 48 EditData.BoilingPoint = tmp; 49 await InvokeAsync(StateHasChanged); 50 } 51 52 protected async Task OnValueChangeHandler2(string newValue) 53 { 54 double set_val = 0.0; 55 if (!double.TryParse(newValue, out set_val)) 56 { 57 return; 58 } 59 60 //入れ直してStateHasChangedしても効果無し 61 EditData.BoilingPoint = set_val; 62 double tmp = EditData.MeltingPoint; 63 EditData.MeltingPoint = EditData.MeltingPoint + 1.0; 64 await InvokeAsync(StateHasChanged); 65 EditData.MeltingPoint = tmp; 66 await InvokeAsync(StateHasChanged); 67 } 68 69 void Submit() => MudDialog?.Close(DialogResult.Ok(true)); 70 void Cancel() => MudDialog?.Cancel(); 71}
MudBlazorを使わずEditFormを使うなら以下のようになるでしょうか?
この場合はフォーカス移動だけで無く、値を入れ直さないとバリデーションチェックが走りませんでした。
操作例:
1.Melting pointに1を設定してフォーカスをBoiling pointに移動
→Melting pointのバリデーションメッセージ表示
2.Boiling pointに-255を設定してフォーカスをMelting pointに移動
→Boiling pointのバリデーションメッセージ表示
3.Melting pointに-999を設定してフォーカスをBoiling pointに移動
→Melting pointのバリデーションメッセージ表示が消えるがBoiling pointのバリデーションメッセージはそのまま。
4.Boiling pointの値を変えずにSaveボタンにフォーカスを移動
→変化無し
5.Boiling pointに-255を設定してSaveボタンにフォーカスを移動
→Boiling pointのバリデーションメッセージ表示が消える。
Razor
1@using System.Globalization 2@using MudDataGridSample.Data 3 4<EditForm Model="@EditData" @ref="form" OnValidSubmit="@Submit"> 5 <DataAnnotationsValidator /> 6 <div> 7 <label>Name</label> 8 <InputText @bind-Value="EditData.Name"></InputText> 9 <ValidationMessage For="@(() => EditData.Name)" /> 10 </div> 11 <br /> 12 <div> 13 <label>Melting point</label> 14 <InputNumber TValue="Double" @bind-Value="EditData.MeltingPoint" /> 15 <ValidationMessage For="@(() => EditData.MeltingPoint)" /> 16 </div> 17 <br /> 18 <div > 19 <label >Boiling point</label> 20 <InputNumber TValue="Double" @bind-Value="EditData.BoilingPoint" /> 21 <ValidationMessage For="@(() => EditData.BoilingPoint)" /> 22 </div> 23 <br /> 24 <div > 25 <input type="submit" value="Save" /> 26 </div> 27</EditForm> 28 29@code { 30 EditForm? form; 31 32 public Element EditData { get; set; } = new Element { Name = "Hydrogen", MeltingPoint = -259.14, BoilingPoint = -252.87 }; 33 34 private async Task Submit() 35 { 36 37 await InvokeAsync(StateHasChanged); 38 } 39}
試したこと
- TextChangedイベントで値を入れ直してStateHasChangedを呼んでも効果はありませんでした。
回答3件
あなたの回答
tips
プレビュー