Для ссздания компонента в Blazor достаточно создать некоторую папку (рекомендуется - "Components"; как вариант, его можно разместить в папке "Shared") и создать в папке файл с разрешением ".razor". В этом файле может быть определена как разметка, так и методы с атрибутами. Например:
<h2>New Pizza: @PizzaName</h2>
<p>@PizzaDescription</p>
@code {
[Parameter]
public string PizzaName { get; set; }
[Parameter]
public string PizzaDescription { get; set; } = "The best pizza you've ever tasted.";
}
В приведённом выше примере определено два дочерних свойства компонента: PizzaName и PizzaDescription. Эти свойства может устанавливать родительский компонент.
Мы можем задавать значения по умолчанию, это сделано для атрибута PizzaDescription.
Если мы хотим использовать этот компонент, то мы можем указать a fully qualified name компонента и набор атрибутов. Например:
<BlazorWasmApp.Components.Pizza PizzaName="123" PizzaDescription="The cool pizza" />
Чтобы не указывать полное имя компонента, следует использовать директиву @using
:
@using BlazorWasmApp.Components;
...
<Pizza PizzaName="123" PizzaDescription="The cool pizza" />
Также можно определить класс с атрибутами и использовать их в рамках компонентной модели:
public class PizzaTopping
{
public string Name { get; set; }
public string Ingredients { get; set; }
}
Пример использования:
<h2>New Topping: @Topping.Name</h2>
<p>Ingredients: @Topping.Ingredients</p>
@code {
[Parameter]
public PizzaTopping Topping { get; set; }
}
В родительном классе передача параметров может выглядеть следующим образом:
@page "/pizzas-toppings"
<h1>Our Latest Pizzas and Topping</h1>
<Pizza PizzaName="Hawaiian" PizzaDescription="The one with pineapple" />
<PizzaTopping Topping="@(new PizzaTopping() { Name = "Chilli Sauce", Ingredients = "Three kinds of chilli." })" />
В Razoe можно определить стили и cs-файлы, которые будут видны только внутри конкретного компонента. Предположим, что у нас есть компонент с именем "mycomponent". Мы можем разместить в том же самом подкаталоге, в котором находится razor-файл ещё один файл с именем "mycomponent.styles.css" и стили, определённые в этой файле, будут применены только к этому конкретному компоненту.
Общие для разных компонентов стили определяются в файле "[ИмяПроекта].styles.css".
Также можно создать cs-файл и включить в него некоторую логику. Клитичным является использование ComponentBase
в качестве базового класса:
public class Component1Logic : ComponentBase
{
// ...
}
Для того, чтобы связать такой cs-файл с razor-файлов потребуется в последнем добавить строку:
@inherits Component1Logic
В Blazor существует возможность передать значение параметра не конкретному дочернему компоненту, а вниз, по всей иерархии от родительского ко всем вложенным дочерним компонентам. Этот механизм называется Каскадные параметры.
В родительском компоненте добавляется специальный тэг CascadingValue
, который указывает, что некоторые параметры следует передать всем дочерним элементам по всей иерархии. Например:
@page "/specialoffers"
<h1>Special Offers</h1>
<CascadingValue Name="DealName" Value="Throwback Thursday">
<!-- Любой дочерний компонент, не смотря на его уровень вложенности получит этот параметр -->
</CascadingValue>
Чтобы компонент получил такой параметр, следует определить специальный атрибут:
<h2>Deal: @DealName</h2>
@code {
[CascadingParameter(Name="DealName")]
private string DealName { get; set; }
}
Стоит повторить: CascadingValue - это компонент, а CascadingParameter - это атрибут!
Родительский компонент:
@using BlazoServerApp.Components.Shared;
<CascadingValue Value="@Style">
<ChildComponent></ChildComponent>
</CascadingValue>
@code {
public string Style { get; set; } = "color:green";
}
Дочерний элемент (ChildComponent.razor):
@using BlazoServerApp.Components.Shared;
<h1 style="@ElementStyle">-Child Component</h1>
<GrandChildComponent></GrandChildComponent>
@code {
[CascadingParameter]
public string ElementStyle { get; set; }
}
"Внучатый" элемент (GrandChildComponent.razor):
<h1 style="@ElementStyle">--Grand Child Component Text</h1>
@code {
[CascadingParameter]
public string ElementStyle { get; set; }
}
Если мы поменяем переменную Style в родительском элементе, то она поменяется и во всех дочерних элементах:
<button class="btn btn-primary" @onclick="ChangeColor">Click me</button>
@code {
private void ChangeColor()
{
Style = "color:red;";
}
}
Механизм удобно использовать для поддержки тем пользовательского интерфейса:
<CascadingValue Value="@theme">
<Router ...>
...
</Router>
</CascadingValue>
@code {
private ThemeInfo theme = new() { ButtonClass = "btn-success" };
}
Можно применять несколько каскадных значений:
<CascadingValue Value="@parentCascadeParameter1" Name="CascadeParam1">
<CascadingValue Value="@ParentCascadeParameter2" Name="CascadeParam2">
...
</CascadingValue>
</CascadingValue>
Эти значения будут транслироваться в различные каскадные параметры:
@code {
[CascadingParameter(Name = "CascadeParam1")]
protected CascadingType? ChildCascadeParameter1 { get; set; }
[CascadingParameter(Name = "CascadeParam2")]
protected CascadingType? ChildCascadeParameter2 { get; set; }
}
Портал learn.microsoft.com содержит материалы по добавлению AppState для Blazor Server.
Общая идея состоит в том, что разрабатывается класс, в котором хранится некоторое состояние. Например:
public class PizzaSalesState
{
public int PizzasSoldToday { get; set; }
}
Затем, используя механизм Dependency Injection, добавляется сервис, который можно затем внедрять в разные страницы:
// Add services to the container
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
// Add the AppState class
builder.Services.AddScoped<PizzaSalesState>();
Внедрение состояния и его использование выглядит следующим образом:
@page "/"
@inject PizzaSalesState SalesState
<h1>Welcome to Blazing Pizzas</h1>
<p>Today, we've sold this many pizzas: @SalesState.PizzasSoldToday</p>
<button @onclick="IncrementSales">Buy a Pizza</button>
@code {
private void IncrementSales()
{
SalesState.PizzasSoldToday++;
}
}
Тоже самое можно сделать и для Blazor Web Assembly, см. демонстрационное приложение.
Справочная информация доступна по ссылке.
Регистрация зависимостей выполняется в файле "Program.cs" и может выглядеть следующим образом:
builder.Services.AddSingleton<NotifierService>();
builder.Services.AddSingleton<TimerService>();
builder.Services.AddSingleton<IDataAccess, DataAccess>();
builder.Services.AddSingleton<IProductRepository, ProductRepository>();
Определение интерфейса может выглядеть, например, так:
public interface IUserService
{
public string? Name { get; set; }
}
public interface ISettingService
{
public IList<Setting> GetSettings();
}
Или так:
@code {
...
public interface IDataAccess
{
public Task<IReadOnlyList<Actor>> GetAllActorsAsync();
}
public class DataAccess : IDataAccess
{
public Task<IReadOnlyList<Actor>> GetAllActorsAsync() =>
Task.FromResult(GetActors());
}
...
}
Сохранять классы, отвечающие за State Management рекомендуется в папке "Services".
Внедрение зависимости может осуществляться на странице ".razor":
@page "/the-sunmakers"
@inject IDataAccess DataRepository
...
@if (actors != null)
{
<ul>
@foreach (var actor in actors)
{
<li>@actor.FirstName @actor.LastName</li>
}
</ul>
}
Компонент создаётся когда пользователь заходит на страницу и удаляется, когда пользователь уходит с неё.
Основные события связанные с жизненным циклом:
- SetParametersAsync: вызывается когда устанавливаются параметры, задаваемые родительским элементом
- OnInitialized / OnInitializedAsync: вызываются, когда компонент готов к запуску
- OnParametersSet / OnParametersSetAsync: вызываются, когда устанавливаются параметры компонента
- OnAfterRender / OnAfterRenderAsync: вызывается после "отрисовки" элемента
- Dispose / DisposeAsync: вызывается при удалении объекта (если реализован интерфейс IDisposable, или IAsyncDisposable)
Библиотека классов Razor — это тип проекта .NET, содержащий компоненты Razor, страницы, HTML, файлы Cascading Style Sheet (CSS), JavaScript, изображения и другое статическое веб-содержимое, на которое может ссылаться приложение Blazor.
"Библиотека классов" и "Библиотека классов Razor" — это разные, но связанные вещи. "Библиотека классов Razor" является более специализированной, чем "Библиотека классов".
Проект Библиотека классов Razor создаётся из соответствующего шаблона в Visual Studio/Visual Studio Code. Например, командой:
dotnet new razorclasslib -o MyProjectName
Типовой компонент, максимально простой - он содержит div и что-то внутри него, например:
<div class="my-component">
This component is defined in the <strong>FirstRazorLibrary</strong> library.
</div>
Мы можем добавить разработанную библиотеку классов Razor в проект, как ссылку (Reference). Сделать это можно, например, командой:
dotnet add reference ../MyClassLibrary
Мы можем оформить компонент, также как и NuGet-package. В этом случае, включить зависимость можно следующей командой:
dotnet add package MyClassLibrary
Хорошими кандидатами на создание библиотек классов Razor являются модальные диалоги.