Еще одной полезной возможностью Blazor является то, что компонент-предок может предоставить каскадный параметр с помощью компонента CascadingValue, который заключает поддерево иерархии компонентов и предоставляет одно значение для всех компонентов в его поддереве.
Использование компонента CascadingValue
Одним из возможных вариантов использования компонента CascadingValue является кастомизация темы оформления вашего приложения. Например, рассмотрим стандартный шаблон приложения Blazor Server в состав которого входит компонент счётчика, таблица с данным о метеоусловиях и компонент опроса. Для изменения стиля отрисовки каждого элемента мы могли бы задавать каждый стиль по-отдельности вручную, а можем воспользоваться каскадным параметром с использованием CascadingValue. Чтобы продемонстрировать как работает этот компонент выполним следующие действия:
1. Создадим новый класс ThemeTemplate со следующими свойствами:
namespace BlazorApp1
{
public class ThemeTemplate
{
public string ButtonStyle { get; set; }
public string TableStyle { get; set; }
}
}
Этот класс будет содержать CSS-стили кнопок и таблиц нашего приложения.
2. В макете приложения (файл MainLayout.razor) используем CascadingValue
@inherits LayoutComponentBase
<PageTitle>BlazorApp1</PageTitle>
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<CascadingValue Value="template">
<article class="content px-4">
@Body
</article>
</CascadingValue>
</main>
</div>
@code
{
ThemeTemplate template = new ThemeTemplate()
{
ButtonStyle = "btn-danger",
TableStyle = "table table-dark table-striped"
};
}
3. Чтобы дочерние компоненты могли воспользоваться каскадным параметром, компоненты-потомки объявляют каскадные параметры с помощью атрибута [CascadingParameter]. Каскадные значения привязаны к каскадным параметрам по типу. Объявим такие параметры на страницах Counter.razor и FetchData.razor
Страница Counter.razor:
@page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn @Template.ButtonStyle" @onclick="IncrementCount">Click me</button>
@code {
[CascadingParameter]
public ThemeTemplate Template { get; set; }
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
Страница FetchData.razor:
@page "/fetchdata"
<PageTitle>Weather forecast</PageTitle>
@using BlazorApp1.Data
@inject WeatherForecastService ForecastService
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from a service.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="@Template.TableStyle">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
[CascadingParameter]
public ThemeTemplate Template { get; set; }
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
}
}
Теперь можем запустить приложение и посмотреть как изменится стиль кнопки и таблицы:

Таблица с каскадным параметром:

Каскадное применение нескольких значений
Чтобы выполнить каскадное применение нескольких значений одного типа в одном поддереве, необходимо указать уникальную строку Name для каждого компонента CascadingValue и его соответствующих атрибутов [CascadingParameter]. Например добавим ещё одну тему оформления:
Файл MainLayout.razor
@inherits LayoutComponentBase
<PageTitle>BlazorApp1</PageTitle>
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<CascadingValue Value="template" Name="MainTheme">
<CascadingValue Value="otherTemplate" Name="SecondTheme">
<article class="content px-4">
@Body
</article>
</CascadingValue>
</CascadingValue>
</main>
</div>
@code
{
ThemeTemplate template = new ThemeTemplate()
{
ButtonStyle = "btn-danger",
TableStyle = "table table-dark table-striped"
};
ThemeTemplate otherTemplate = new ThemeTemplate()
{
ButtonStyle = "btn-success",
TableStyle = "table table-dark table-striped"
};
}
Файл Counter.razor— применим вторую тему оформления
///Код компонента/////
<button class="btn @Template.ButtonStyle" @onclick="IncrementCount">Click me</button>
@code {
@*Применяем вторую тему оформления*@
[CascadingParameter(Name ="SecondTheme")]
public ThemeTemplate Template { get; set; }
///Код компонента/////
}
Файл FetchData.razor— оставим тему оформления из предыдущего примера
///Код компонента/////
<table class="@Template.TableStyle">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
[CascadingParameter(Name ="MainTheme")]
public ThemeTemplate Template { get; set; }
///Код компонента/////
}
Результат применения новой темы для кнопки:
Итого
Каскадные параметры в Blazor можно задать с использованием компонента CascadingValue. Каскадный параметр может использовать любой компонент в дереве иерархии компонента-родителя. Для использования нескольких каскадных параметров, имеющих один и тот же тип значений у компонента CascadingValue необходимо определять уникальный параметр Name.
