Blazor InputFile reset/clear 值 - statehaschanged() 不工作

Blazor InputFile reset/clear value - statehaschanged() not working

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

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

所以,我想如果我可以 select 一个文件并调用 OnChange 处理程序并在 OnChange 处理程序中“重置” selected 文件,那么我应该得到一个新的调用处理程序,即使同一个文件再次被 selected。

我不知道如何重置 InputFile(子)组件中的文件 selection。在处理程序中调用 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
    }

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

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

@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
}

晚会有点晚了,但我 运行 遇到了与 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);
}

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

将 InputFile 包装在一个布尔值中以暂时 hide/show。这会清除值。

@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();
    }
}

您可以将 @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;
    }

}```