带有文件的 Blazor Webassembly (.NET 5) 自定义组件:验证不起作用
Blazor Webassembly (.NET 5) customized component with files: validation does not work
我发现 Chris Sainty 的这个很棒 post:Creating Bespoke Input Components for Blazor from Scratch。这正是我需要的,但不是 string
,而是上传的文件 IBrowserFile
。所以我已经为我改编和扩展了这个例子。自定义组件显示新文件并将其保存在我的模型中,但不幸的是 CSS 状态保持在 class="modified invalid"
。
我一定在这里遗漏了一个小细节。它是什么?提前感谢您的任何提示。
这是我的代码,只保留了基本要素。
Selection.razor
@page "/selection"
@inherits ParentComponent<SelectionTestModel>
<PageComponent @ref="Page" Model="Model" StatusCode="StatusCode" PageType="PageType.Touch">
<PageBody>
<EditForm Model="Model" OnValidSubmit="Save">
<DataAnnotationsValidator />
<DocumentComponent @ref="DocumentUpload" @bind-Documents="Model.Files" />
</EditForm>
</PageBody>
</PageComponent>
@code {
private DocumentComponent DocumentUpload;
}
SelectionTestModel.cs
public class SelectionTestModel
{
public int? KeyID { get; set; }
/* ... */
[System.ComponentModel.DisplayName("Document")]
[System.ComponentModel.DataAnnotations.Display(Name = "Document")]
[System.ComponentModel.DataAnnotations.Range(2, 2, ErrorMessage = "You have to bring exactly two files!")]
public List<DocumentModel> Files { get; set; } = new List<DocumentModel>();
}
文档模型
public class DocumentModel
{
public int? Id { get; set; }
public string Reference { get; set; }
public string Name { get; set; }
public long Size { get; set; }
public string ContentType { get; set; }
public string Content { get; set; } /*file as base64 string*/
}
DocumentComponent.razor
@using System.Linq.Expressions
<div class="dropzone rounded @_dropClass @_validClass">
<InputFile id="inputDrop" multiple
ondragover="event.preventDefault()"
ondragstart="event.dataTransfer.setData('', event.target.id)"
accept="@AllowedFileTypes"
OnChange="OnInputFileChange"
@ondragenter="HandleDragEnter"
@ondragleave="HandleDragLeave" />
@*...*@
</div>
@code {
[CascadingParameter] public EditContext EditContext { get; set; }
[Parameter] public List<DocumentModel> Documents { get; set; } = new List<DocumentModel>();
[Parameter] public EventCallback<List<DocumentModel>> DocumentsChanged { get; set; }
[Parameter] public Expression<Func<List<DocumentModel>>> DocumentsExpression { get; set; }
/*...*/
public List<string> AllowedFileTypes { get; set; } = new List<string> { ".pdf", /*...*/ };
private FieldIdentifier _fieldIdentifier;
private string _validClass => EditContext?.FieldCssClass(_fieldIdentifier) ?? null;
protected override void OnInitialized()
{
base.OnInitialized();
_fieldIdentifier = FieldIdentifier.Create(DocumentsExpression);
}
private async Task OnInputFileChange(InputFileChangeEventArgs e)
{
// validation: do we accept the file (content type, amount of files, size)
if (e.FileCount == 1) // keep it simple for this example
{
// read from IBrowserFile and return DocumentModel in memory only
Documents.Add(await SaveFile(e.File));
await DocumentsChanged.InvokeAsync(Documents);
EditContext?.NotifyFieldChanged(_fieldIdentifier);
}
}
/*...*/
}
它在浏览器中的表现如何 (Chrome)
加载页面后,一切看起来都符合预期。
之后我上传了一个文件。所以我有一个文件,我希望有两个。验证变成红色,我得到“修改无效”。到目前为止一切都很好。
最后我将另一个文件拖入组件中并得到两个文件。我也可以在模型中看到这一点。但不幸的是,class 属性“modified valid”没有设置。
再次感谢您的建议
我在错误的方向上挖得太深,没有看到明显的东西。
问题是模型中有一个属性集不会抛出错误,但也无法验证。
Range 属性不适用于列表,因此模型永远无法验证。有了自己的属性,我可以解决这个问题。
SelectionTestModel.cs
[Library.Validation.Attribute.ListRange(2, 2)]
public List<DocumentModel> Files { get; set; } = new List<DocumentModel>();
ListRangeAttribute.cs
namespace Library.Validation.Attribute
{
public class ListRangeAttribute : ValidationAttribute
{
public int Minimum { get; set; }
public int Maximum { get; set; }
public ListRangeAttribute(int minimum = 0, int maximum = int.MaxValue)
{
Minimum = minimum > 0 ? minimum : 0;
Maximum = maximum;
}
public string GetErrorMessage(string displayName) { /* ... */ }
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var list = value as IList;
if (list == null)
{
throw new InvalidOperationException($"Attribute {nameof(ListRangeAttribute)} must be on a property of type {nameof(IList)}.");
}
if ((list?.Count ?? 0) < Minimum || (list?.Count ?? int.MaxValue) > Maximum)
{
return new ValidationResult(GetErrorMessage(validationContext.DisplayName), new[] { validationContext.MemberName });
}
return ValidationResult.Success;
}
}
}
希望这篇post可以帮助到其他人
剩余: 现在给我留下了一个新的谜团。
为什么单击保存按钮后验证文本消失,由于模型状态无效而无法保存!?
我发现 Chris Sainty 的这个很棒 post:Creating Bespoke Input Components for Blazor from Scratch。这正是我需要的,但不是 string
,而是上传的文件 IBrowserFile
。所以我已经为我改编和扩展了这个例子。自定义组件显示新文件并将其保存在我的模型中,但不幸的是 CSS 状态保持在 class="modified invalid"
。
我一定在这里遗漏了一个小细节。它是什么?提前感谢您的任何提示。
这是我的代码,只保留了基本要素。
Selection.razor
@page "/selection"
@inherits ParentComponent<SelectionTestModel>
<PageComponent @ref="Page" Model="Model" StatusCode="StatusCode" PageType="PageType.Touch">
<PageBody>
<EditForm Model="Model" OnValidSubmit="Save">
<DataAnnotationsValidator />
<DocumentComponent @ref="DocumentUpload" @bind-Documents="Model.Files" />
</EditForm>
</PageBody>
</PageComponent>
@code {
private DocumentComponent DocumentUpload;
}
SelectionTestModel.cs
public class SelectionTestModel
{
public int? KeyID { get; set; }
/* ... */
[System.ComponentModel.DisplayName("Document")]
[System.ComponentModel.DataAnnotations.Display(Name = "Document")]
[System.ComponentModel.DataAnnotations.Range(2, 2, ErrorMessage = "You have to bring exactly two files!")]
public List<DocumentModel> Files { get; set; } = new List<DocumentModel>();
}
文档模型
public class DocumentModel
{
public int? Id { get; set; }
public string Reference { get; set; }
public string Name { get; set; }
public long Size { get; set; }
public string ContentType { get; set; }
public string Content { get; set; } /*file as base64 string*/
}
DocumentComponent.razor
@using System.Linq.Expressions
<div class="dropzone rounded @_dropClass @_validClass">
<InputFile id="inputDrop" multiple
ondragover="event.preventDefault()"
ondragstart="event.dataTransfer.setData('', event.target.id)"
accept="@AllowedFileTypes"
OnChange="OnInputFileChange"
@ondragenter="HandleDragEnter"
@ondragleave="HandleDragLeave" />
@*...*@
</div>
@code {
[CascadingParameter] public EditContext EditContext { get; set; }
[Parameter] public List<DocumentModel> Documents { get; set; } = new List<DocumentModel>();
[Parameter] public EventCallback<List<DocumentModel>> DocumentsChanged { get; set; }
[Parameter] public Expression<Func<List<DocumentModel>>> DocumentsExpression { get; set; }
/*...*/
public List<string> AllowedFileTypes { get; set; } = new List<string> { ".pdf", /*...*/ };
private FieldIdentifier _fieldIdentifier;
private string _validClass => EditContext?.FieldCssClass(_fieldIdentifier) ?? null;
protected override void OnInitialized()
{
base.OnInitialized();
_fieldIdentifier = FieldIdentifier.Create(DocumentsExpression);
}
private async Task OnInputFileChange(InputFileChangeEventArgs e)
{
// validation: do we accept the file (content type, amount of files, size)
if (e.FileCount == 1) // keep it simple for this example
{
// read from IBrowserFile and return DocumentModel in memory only
Documents.Add(await SaveFile(e.File));
await DocumentsChanged.InvokeAsync(Documents);
EditContext?.NotifyFieldChanged(_fieldIdentifier);
}
}
/*...*/
}
它在浏览器中的表现如何 (Chrome)
加载页面后,一切看起来都符合预期。
之后我上传了一个文件。所以我有一个文件,我希望有两个。验证变成红色,我得到“修改无效”。到目前为止一切都很好。
最后我将另一个文件拖入组件中并得到两个文件。我也可以在模型中看到这一点。但不幸的是,class 属性“modified valid”没有设置。
再次感谢您的建议
我在错误的方向上挖得太深,没有看到明显的东西。
问题是模型中有一个属性集不会抛出错误,但也无法验证。 Range 属性不适用于列表,因此模型永远无法验证。有了自己的属性,我可以解决这个问题。
SelectionTestModel.cs
[Library.Validation.Attribute.ListRange(2, 2)]
public List<DocumentModel> Files { get; set; } = new List<DocumentModel>();
ListRangeAttribute.cs
namespace Library.Validation.Attribute
{
public class ListRangeAttribute : ValidationAttribute
{
public int Minimum { get; set; }
public int Maximum { get; set; }
public ListRangeAttribute(int minimum = 0, int maximum = int.MaxValue)
{
Minimum = minimum > 0 ? minimum : 0;
Maximum = maximum;
}
public string GetErrorMessage(string displayName) { /* ... */ }
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var list = value as IList;
if (list == null)
{
throw new InvalidOperationException($"Attribute {nameof(ListRangeAttribute)} must be on a property of type {nameof(IList)}.");
}
if ((list?.Count ?? 0) < Minimum || (list?.Count ?? int.MaxValue) > Maximum)
{
return new ValidationResult(GetErrorMessage(validationContext.DisplayName), new[] { validationContext.MemberName });
}
return ValidationResult.Success;
}
}
}
希望这篇post可以帮助到其他人
剩余: 现在给我留下了一个新的谜团。 为什么单击保存按钮后验证文本消失,由于模型状态无效而无法保存!?