Как осуществляется передача данных от родительских компонентов в дочерние с использованием каскадных параметров в Blazor мы уже знаем. При этом, вполне возможна необходимость и в обратном — передача данных от дочернего компонента в родительский. Сегодня мы рассмотрим вопрос про совместное использование данных дочерними и родительскими компонентами в Blazor и научимся передавать данные из дочернего компонента к предку.
Рассмотрим следующую, достаточно распространенную, ситуацию: в приложении есть список сущностей (например, книг, телефонов и т.д.), каждая сущность имеет свой набор параметров, которые необходимо отобразить пользователю на экране. Соответственно, в приложении у нас есть два компонента:
- дочерний — представляет собой конкретную сущность
- родительский — список сущностей (это может быть как обычный список, так и таблица — сути это не меняет)
у нас есть задача — сортировать список сущностей по различным признакам, которые пользователь выбирает, например, кликая мышкой по соответствующему параметру сущности в списке.
Создадим такое приложение Blazor Hybrid, используя в качестве сущности, например, телефон. Для начала, создадим необходимую модель (класс) телефона. Для этого, создадим в папке Data
файл Phone.cs
со следующим содержимым:
namespace PhoneManager.Data { public class Phone { /// <summary> /// Название телефона /// </summary> public string Name { get; set; } /// <summary> /// Операционная система /// </summary> public string OS { get; set; } /// <summary> /// Цена телефона /// </summary> public int Price { get; set; } } }
Теперь создадим компонент Razor, который будет представлять информацию по одному телефону. Назовем его PhoneItem.razor
:
@using PhoneManager.Data; @if (PhoneData != null) { <div class="container"> <div class="row-sm-12" @onclick="@(()=>PhoneElementClick(SortData.Name))"> <b>@PhoneData.Name</b> </div> <div class="col-sm-6"> Операционная система: <button class="btn btn-link" @onclick="@(()=>PhoneElementClick(SortData.OS))">@PhoneData.OS</button> </div> <div class="col-sm-6" @onclick="@(()=>PhoneElementClick(SortData.Price))"> Цена: @PhoneData.Price </div> </div> } @code { [Parameter] public Phone PhoneData { get; set; } [Parameter] public EventCallback<SortData> PhoneClick { get; set; } public async Task PhoneElementClick(SortData data) { await PhoneClick.InvokeAsync(data); } }
Рассмотрим более подробно этот компонент. Во-первых, у компонента определены два параметра:
public Phone PhoneData { get; set; }
Содержит информацию по телефону, которую необходимо показать пользователю.
[Parameter] public EventCallback<SortData> PhoneClick { get; set; }
С помощью этого параметра компонента Blazor мы будем вызывать метод родительского компонент для сортировки списка элементов. При этом, тип SortData
будет содержать сведения о том, по какому критерию сортируется список и выглядит следующим образом:
public enum SortData { Name, Price, OS }
У некоторых элементов <div> в разметке компонента определены обработчики события click
:
@onclick="@(()=>PhoneElementClick(SortData.Name))
Таким образом, клик по элементу будет вызывать метод родительского компонента, который мы передадим дочернему в параметре PhoneClick
.
Напишем родительский компонент PhoneList
:
@using PhoneManager.Data <h3>Список телефонов</h3> @if (Phones != null) { @sort <br> <div class="container"> @foreach (Phone phone in Phones) { <div class="row-sm"> <PhoneItem PhoneData="@phone" PhoneClick="@ClickPhone"></PhoneItem> <hr> </div> } </div> } @code { [Parameter] public List<Phone> Phones { get; set; } string sort = ""; private void ClickPhone(SortData data) { switch (data) { case SortData.Name: { Phones = Phones.OrderBy(o => o.Name).ToList(); sort = "Список отсортирован по названию"; break; } case SortData.OS: { Phones = Phones.OrderBy(o => o.OS).ToList(); sort = "Список отсортирован по операционной системе"; break; } case SortData.Price: { Phones = Phones.OrderBy(o => o.Price).ToList(); sort = "Список отсортирован по цене"; break; } } } }
Этот компонент принимает один параметр — список телефонов, а также, содержит метод обратного вызова (ClickPhone
), который будет срабатывать при кликах на определенные элементы в компоненте PhoneItem
. Метод обратного вызова назначается в этой строке:
<PhoneItem PhoneData="@phone" PhoneClick="@ClickPhone"></PhoneItem>
Теперь откроем главную страницу приложения (Index.razor
) и добавим на неё наш компонент PhoneList
:
@page "/" @using PhoneManager.Data <PhoneList Phones="@phones"></PhoneList> @code { List<Phone> phones = new() { new() { Name = "Xiaomi", OS = "Android 13", Price = 40000 }, new() { Name = "Samsung", OS = "Android 14", Price = 50000 }, new() { Name = "LG", OS = "Android 9", Price = 60000 }, new() { Name = "Honor", OS = "Android 10", Price = 12000 }, new() { Name = "IPhone", OS = "iOS", Price = 120000 }, }; }
Здесь мы в коде компонента создаем список телефонов, а в разметке — передаем его компоненту PhoneList
. Запустим приложение и убедимся, что всё работает:

Теперь нажмем на название телефона, операционную систему или цену и увидим, что список отсортируется по заданному критерию:

Итого
Таким образом, совместное использование данных дочерними и родительскими компонентами в Blazor осуществляется путем использования методов обратного вызова, которые назначаются дочерним компонентам через структуру EventCallback<T>
. Используя EventCallback<T>
, мы можем передавать в родительский компонент любую необходимую информацию — строки, числа, объекты и так далее. Родительский компонент будет обрабатывать полученную информацию и автоматически перерисовывать себя без дополнительных вызовом метода StateHasChanged
.