简体   繁体   中英

Binding files selected with InputFile in Blazor

I'm trying to data bind some user-selected files in the Blazor InputFile component, specifically the AssociatedFiles property of each ToDoItem . This is not working because the AssociatedFiles is always null .

This is my razor component:

@page "/todo"

@using BlazorPlayground.Data

<h3>Todo List</h3>
Total items: @todos.Count()
<br />
Done: @todos.Count(x => x.IsDone) out of @todos.Count()
<br />
Not Done: @todos.Count(x => !x.IsDone) out of @todos.Count()
<br />

<ul>
    @foreach (var todo in todos)
    {
        <li>
            <input type="checkbox" @bind="todo.IsDone" />
            <input @bind="todo.Title" />
            <input type="datetime-local" @bind="todo.DateAdded" />
            <InputFile OnChange="@OnFileSelected" @bind-value="todo.AssociatedFiles" multiple  />
        </li>
    }
</ul>


<input placeholder="Write something to do..." @bind="newTodo" />
<button @onclick="AddTodo">Add Todo Item</button>

@code {
    private IList<TodoItem> todos = new List<TodoItem>();
    private string newTodo;

    private void AddTodo()
    {
        if (!String.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem(newTodo));
            newTodo = "";
        }
    }

    private void OnFileSelected(InputFileChangeEventArgs e)
    {
    }
}

This is my ToDoItem class:

namespace BlazorPlayground.Data
{
    public class TodoItem
    {
        public string Title { get; set; }
        public bool IsDone { get; set; }
        public DateTime DateAdded { get; set; }
        public IReadOnlyList<IBrowserFile> AssociatedFiles {get; set;}

        public TodoItem(string title)
        {
            this.Title = title;
            this.IsDone = false;
            this.DateAdded = DateTime.Now;
        }
    }
}

By the way, you may have noticed that this is an extension of the Blazor todo list app tutorial .

Never done that before, but I guess this should work...

<InputFile OnChange="@((InputFileChangeEventArgs args) => OnFileSelected(args, todo))" multiple  />

Get the selected files, and add them to the AssociatedFiles field of the current TodoItem object

private void OnFileSelected (InputFileChangeEventArgs e, TodoItem todo)
{
    var selectedFiles = e.GetMultipleFiles();
    todo.AssociatedFiles = selectedFiles;
    this.StateHasChanged();
}

UPDATE

I'm quite new to web development and I didn't know that you could pass anonymous functions to the OnChange attribute there.

It's a lambda expression...

I thought you were supposed to enter the name of a method there.

The InputFile component exposes an EventCallback property like this:

[Parameter] public EventCallback OnChange { get; set; }

Usually you assign the name of your event handler to the property attribute like the following:

<InputFile OnChange="OnInputFileChange" multiple />

And use it like this:

private void OnInputFileChange (InputFileChangeEventArgs e)
{
     selectedFiles = e.GetMultipleFiles();
     message = $"{selectedFiles.Count} file(s) selected";
     this.StateHasChanged();
}

You may use a lambda expression as the value of the OnChange attribute, as done below... but in that case it's your responsibility to pass the InputFileChangeEventArgs argument to your event handler ( OnInputFileChange )

<InputFile OnChange="@((InputFileChangeEventArgs args) => 
                                   OnInputFileChange(args))" multiple  />

This of course is over skill and really superfluous. But if you want to pass a second parameter to your event handler, as in the case of your question, this approach is the correct one.

I think your problem is related with foreach. Cuz when you use foreach it added additional prefix, that can be problem why your model can't binded

So I recommend your replace foreach on for and checkout again

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM