Обновление пользовательского интерфейса Blazor внутри цикла для каждого компонента

#c# #blazor

Вопрос:

У меня есть компоненты Blazor, похожие на это:

Главная.бритва

 @foreach (Vehicle vehicle in _vehicles) 
{
    if (vehicle.Visible)
    {
        <VehicleComponent Vehicle=@vehicle></VehicleComponent>
    }
}

@code {
    protected override void OnInitialized() 
    {
        _vehicles = new List<Vehicles>();
        // -> _vehicles being filled here
        base.OnInitialized();
    }
}
 

Компонент транспортного средства.бритва

 @if (Vehicle != null) 
{
    <img src="@(Vehicle.src)"/>
    <div id="@(Vehicle.Id)" tabindex="@(Vehicle.tabindex)">
        <h3>@(Vehicle.text)</h3>
    </div>
}

@code {
    [Parameter] public Vehicle Vehicle { get; set; }
}
 

Проблема в том, что все VehicleComponent s внутри цикла отображаются после завершения цикла. Но я хочу, чтобы компонент был полностью отрисован до того, как будет отрисован следующий элемент списка.

Я пробовал использовать StateHasChanged() после каждого элемента Main.razor , но получился бесконечный цикл. Есть ли способ, которым я могу отображать каждый компонент в цикле друг за другом (и обновлять пользовательский интерфейс)?

Комментарии:

1. Почему? [комментарий слишком короткий]

2. Это не причина для обновления пользовательского интерфейса внутри цикла. В любом случае, это не то, что делает опубликованный вами код. Если вы хотите, чтобы отдельные компоненты обновлялись при изменении свойства, свяжите это свойство с параметром компонентов. Это единственный способ, которым компонент может узнать, что, например vehicle.Visible , изменился

3. Что касается rendered after the loop is finished. того, в чем заключается реальная проблема? Этот компонент прост и не должен занимать много времени для визуализации. Вы пытаетесь отобразить гораздо больше элементов, чем может быть отображено? Это плохая идея и вызовет серьезные проблемы с производительностью и прокруткой, независимо от структуры. Вместо этого используйте виртуализацию компонентов , чтобы отображать только видимые строки

4. попробуйте использовать @key=...

5. Если вы используете Virtualize, вы ДОЛЖНЫ убедиться, что элемент — заполнитель шаблона точно соответствует высоте отображаемого элемента списка-если элементы списка различаются по размеру, это не для вас.

Ответ №1:

Если вам нужен визуальный эффект «постепенно появляющихся» предметов:

 protected override async Task OnInitializedAsync () 
{
    var temp =  new List<Vehicles>(); 
    // -> _vehicles being filled here

    _vehicles = new List<Vehicles>();
    foreach (var vehicle in temp)
    {
       _vehicles.Add(vehicle);
       StateHasChanged();
       await task.Delay(500);  // adjust the delay to taste
    }
}
 

но имейте в виду, что это дорогой (медленный) способ показать их.
Использование @key не улучшит ситуацию, но это может помочь, когда вы измените список позже:

  <VehicleComponent @key=vehicle Vehicle=@vehicle></VehicleComponent>
 

Ответ №2:

Я думаю, что вы неправильно понимаете процесс рендеринга.

Ваш код Razor компилируется в класс C#, а ваш Razor компилируется как RenderFragment (делегат) — вы можете увидеть это в obj/Debug/Net5 структуре папок проекта. События компонента «Визуализация» помещают этот делегат в очередь средства визуализации. Средство визуализации выполняет эти делегаты и применяет изменения к DOM средства визуализации. Любые изменения в DOM визуализатора передаются в браузер для изменения его DOM.

Ответ Хенка медленно добавляет элементы в список. Он добавляет событие «Рендеринга» StateHasChanged , а затем выполняет Task.Delay его, чтобы позволить визуализатору повторно отображать список на каждой итерации.