0

我发现了 Chris Sainty 的这篇很棒的帖子:从零开始为 Blazor 创建定制输入组件。这正是我需要的,但不是用string,而是用上传的文件IBrowserFile。所以我已经为我调整和扩展了这个例子。自定义组件显示新文件并将其保存在我的模型中,但在 CSS 中,不幸的是状态保持在class="modified invalid". 我必须在这里遗漏一个小细节。它是什么?提前感谢您的任何提示。

这是我的代码简化为基本要素。

选择.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;
    }

选择测试模型.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)

加载页面后,一切看起来都符合预期。 文档组件 - 0 文件

之后我上传一个文件。所以我有一个文件,我希望有两个。验证变为红色,我得到“修改无效”。到目前为止一切都很好。 文档组件 - 1 个文件

最后我将另一个文件拖到组件中并得到两个文件。我也可以在模型中看到这一点。但不幸的是,没有设置类属性“修改有效”。 DocumentComponent - 2 个文件

再次感谢您的任何建议

4

1 回答 1

0

我在错误的方向上挖得太深,没有看到明显的东西。

问题是模型中有一个属性集不会抛出错误,但也无法验证。Range属性不适用于列表,因此模型永远无法验证。有了自己的属性,我可以解决这个问题。

选择测试模型.cs

    [Library.Validation.Attribute.ListRange(2, 2)]
    public List<DocumentModel> Files { get; set; } = new List<DocumentModel>();

列表范围属性.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;
        }
    }
}

我希望这篇文章可以帮助其他人。

剩余:现在我留下了一个新的谜团。为什么单击保存按钮后验证文本消失,由于模型状态无效而无法保存!?

于 2021-03-23T15:12:52.480 回答