6

我有一个使用 Blazor InputFile 组件作为子组件的组件。

当我选择一个文件时,按预期调用 OnChange 处理程序。但是,如果我两次选择同一个文件,则不会再次调用 OnChange 处理程序(我猜这是预期的,因为选择没有改变,但是我的用例需要这个)。

所以,我想如果我可以选择一个文件并调用 OnChange 处理程序并在 OnChange 处理程序中“重置”选定的文件,那么即使再次选择同一个文件,我也应该对处理程序进行新的调用。

我不知道如何重置 InputFile(子)组件中的文件选择。调用this.StateHasChanged()处理程序不会导致 InputFile 组件重新呈现。

如果没有 JSInterop 并手动将 DOM 输入元素的值字段设置为“”,这是否可行(甚至可以工作)?

我的组件:

@using stuff;

<div class="drag-drop-area">
    Drag and drop file here
    <InputFile OnChange="@OnInputFileChange"></InputFile>
</div>

@code {

    [Parameter]
    public String SomeParam { get; set; } = "";

    private async Task OnInputFileChange(InputFileChangeEventArgs e) {
        // do stuff with file

        // do _something_ here to reset InputFile

        this.StateHasChanged(); //<-- this doesn't cause InputFile re-render
    }

到目前为止,我的尝试包括:

  • 遵循与此相关的各种提示/技巧。StateHasChanged(),即
    • await Task.Delay(1);
    • await InvokeAsync(StateHasChanged);
  • 使用向 InputFile 添加值以AdditionalAttributes.Add(..)查看是否可以强制重新渲染
  • 查看了使用 RenderFragment 动态添加 InputFile 组件,但是在代码中创建 InputFile 的新实例时我无法传递 OnChanged 参数(处理程序),这意味着我不会使用 InputFileChangeEventArgs 进行回调
  • 看着将 InputFile 包装在 EditForm 中以重置表单(Blazor EditForms 显然没有重置功能?)
  • [编辑] 将 Task 和 void 用于 OnInputFileChange
4

4 回答 4

3

仍然不是一个很好的解决方案 - 但更简洁一些并且它有效:

将 InputFile 包裹在一个布尔值中以暂时隐藏/显示。这将清除该值。

  @if (!bClearInputFile)
   {
       <InputFile class="form-control-file" OnChange="@OnInputFileChange" />
   }

   @code
   {
        //Call ClearInputFile whenever value must be cleared.
        private void ClearInputFile()
        {
            bClearInputFile = true;
            StateHasChanged();
            bClearInputFile = false;
            StateHasChanged();
        }
   }
于 2021-09-07T15:30:26.643 回答
2

您可以将 @key 添加到 InputFile 并在处理 OnChange 事件时更改它,而不是调用两次 StateHasChanged:

<InputFile @key=@(_inputFileId) OnChange="@LoadFiles" multiple />

@code {
    private string _inputFileId = Guid.NewGuid().ToString();
    
    private Task LoadFiles(InputFileChangeEventArgs e)
    {
        // load file here

        // the InputFile maintains the file the user has chosen and will ignore importing same file, i.e. you can't import the same file more than once to the inputfile control
        // to fix this the InputFile component key is changed so that blazor sees it as a new component and re-creates it in the browser DOM thereby clearing its state (and the file property of it)
        _inputFileId = Guid.NewGuid().ToString();

        return Task.CompletedTask;
    }

}```
于 2022-01-27T10:39:17.360 回答
1

聚会有点晚了,但我遇到了与 OP 类似的问题,但用例略有不同。但无论哪种方式,解决方案似乎都是直截了当的,并且可能会奏效。只需使用一些老式的 javascript。所以要重置OnChange方法中的输入元素,它看起来像这样:

    [Inject]
    private IJSRuntime _js { get; set; }
    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        IBrowserFile file = e.File;
        if (!ValidateFile(file))
        {
            //clearInput is the name of the javascript function
            //ref-upload is the id given to the InputFile element
            await _js.InvokeVoidAsync("clearInput", "ref-upload");
            return;
        }

    }

然后将以下 javascript 函数拖放到您网站上的某处,例如site.js

function clearInput(inputId) {
    setTimeout(function () {
        var input = document.querySelector("#" + inputId);
        if (input) {
            input.value = "";
        }
    }, 30);
}
于 2021-06-09T18:44:46.763 回答
-1

尝试使用条件语句并在两种条件下呈现相同的内容。更改条件应强制更新。

@if (@reviewMechanism == "IMPORT")
{
    <div>
        <u>Import</u>
        <br />
        <br />
        <div>

            <div class="btn  btn-sm" style="background-color: lightgray; margin-bottom: 5px; width: 250px; margin-left: 0px ">
                <span>
                    <button class="btn  btn-sm" style=" font: smaller; border: solid; border-color: gray; border-width: thin;  background-color: rgba(239, 239, 239, 1.00);  margin-left: 0px"
                            @onclick="DownloadTemplate">
                        Download
                    </button>
                    ReviewTemplate.csv
                </span>
            </div>
            <br />
            <div class="btn  btn-sm" style="font: smaller;  margin-bottom: 5px;  width: 250px ; background-color: lightgray;height: 40px">
                <InputFile OnChange="@LoadFiles" style=" margin-left: 10px"> Pick a File </InputFile>
            </div>
        </div>


    </div>
}
else if (@reviewMechanism == "IMPORT2")
{
    <div>
        <u>Import</u>
        <br />
        <br />
        <div>

            <div class="btn  btn-sm" style="background-color: lightgray; margin-bottom: 5px; width: 250px; margin-left: 0px ">
                <span>
                    <button class="btn  btn-sm" style=" font: smaller; border: solid; border-color: gray; border-width: thin;  background-color: rgba(239, 239, 239, 1.00);  margin-left: 0px"
                            @onclick="DownloadTemplate">
                        Download
                    </button>
                    ReviewTemplate.csv
                </span>
            </div>
            <br />
            <div class="btn  btn-sm" style="font: smaller;  margin-bottom: 5px;  width: 250px ; background-color: lightgray;height: 40px">
                <InputFile OnChange="@LoadFiles" style=" margin-left: 10px"> Pick a File </InputFile>
            </div>
        </div>


    </div>
}

当需要改变时:

    loadedFiles = new Dictionary<IBrowserFile, string>();


    if (reviewMechanism == "IMPORT")
    {
        reviewMechanism = "IMPORT2"; //force render
    }
    else
    {
        if (reviewMechanism == "IMPORT2") reviewMechanism = "IMPORT"; //force render
    }
于 2021-05-25T18:54:16.557 回答