Содержание
В предыдущей части мы рассмотрели обработку событий в html-элементах. По большому счёту, обработка событий компонентов Razor практически ничем не отличается от рассмотренного ранее механизма, но в этой части мы немного глубже погрузимся в вопросы обработки событий в Razor
Обработчики событий в Razor
Посмотрим ещё раз на обработчик события Click
у кнопки компонента Counter
в шаблонном приложении Blazor Hybrid:
Чтобы передавать события между родительскими и дочерними компонентами, применяется специальный тип — структура
EventCallback
, которая представлена в двух формах:
EventCallback
EventCallback<T>
В нашем случае использована вторая форма этой структуры — EventCallback<MouseEventArgs>. Если используется такой вид структуры для передачи событий, то обработчик события может принимать аргументы события. Например, в прошлой части мы использовали объект типа MouseEventArgs, чтобы определить какой действие необходимо выполнить — добавить или вычесть единицу из значений счётчика.
По сути, html-элемент button
— это дочерний компонент нашего компонента Razor (в данном случае, компонента Counter
). Поэтому ничто нам не мешает применить точно такой же подход к обработки событий непосредственно между компонентами Razor. Чтобы определить в компоненте Razor какое-либо событие, мы должны создать параметр компонента с типом EventCallback
или EventCallback<T>
, а для обработки этого события в родительском компоненте назначить параметру обработчик.
Обработка событий компонентов Razor
Использование EventCallback
Этот тип применяется, если нашему обработчику события не требуются никакие дополнительные сведения о событии. Создадим новое приложение Blazor Hybrid и изменим код компонента Counter
следующим образом:
@page "/counter" <button class="btn btn-primary" @onclick="OnClick">Click me</button> @code { [Parameter] public EventCallback OnClick { get; set; } }
Теперь перейдем в файл Home.razor
и изменим его код:
@page "/" <h1>Hello, world!</h1> <p>Значение счётчика: @counter</p> <Counter OnClick="IncCounter"></Counter> @code{ int counter = 0; private void IncCounter() { counter++; } }
У компонента Counter
мы создали событие OnClick
:
[Parameter] public EventCallback OnClick { get; set; }
Далее, мы добавили компонент Counter
на страницу Home
, то есть Counter
у нас стал дочерним компонентов для Home
и назначили компоненту обработчик события:
<Counter OnClick="IncCounter"></Counter> @code{ int counter = 0; private void IncCounter() { counter++; } }
Теперь можно запустить приложение и убедиться, что на главной странице при клике по кнопке значение счётчика увеличивается на 1
.
Здесь мы фактически вынесли логику компонента во вне. Давайте немного перепишем компонент Counter
, а заодно посмотрим на ещё один вариант использования собственных событий компонентов Razor. Перепишем код компонента следующим образом:
@page "/counter" <p role="status">Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; [Parameter] public EventCallback OnFullCounter { get; set; } private async Task IncrementCount() { if (currentCount == 10) { await OnFullCounter.InvokeAsync(); } else currentCount++; } }
Здесь мы, по сути, вернули работу Counter
к первоначальному виду. Но, при этом, объявили новое событие:
[Parameter] public EventCallback OnFullCounter { get; set; }
Обратите внимание, как вызывается обработчик этого события:
OnFullCounter.InvokeAsync();
Здесь мы вызываем метод InvokeAsync()
у EventCallback
. Этот метод выполняет делегат, ассоциированный с событием. В нашем случае, как только значение счётчика достигнет 10, будет вызываться обработчик события. Теперь изменим код Home.razor следующим образом:
@page "/" <h1>Hello, world!</h1> @if (showAlert) { <div class="alert alert-danger" role="alert"> Значение счётчика достигло максимального значения </div> } <br /> <Counter OnFullCounter="FullCounter"></Counter> @code{ bool showAlert = false; private void FullCounter() { showAlert = true; } }
Всё, что делает наш обработчик события — это меняет значение у showAlert
с false
на true
. В разметке компонента showAlert
используется для определения того, необходимо ли показывать сообщение пользователю:
@if (showAlert) { <div class="alert alert-danger" role="alert"> Значение счётчика достигло максимального значения </div> }
Теперь запустим приложение и прокликаем кнопку «Click me» десять раз. На одиннадцатый клик сработает обработчик события и мы увидим вот такое сообщение:
И раз уж мы затронули тему использования метода InvokeAsync()
, то теперь можно перейти к рассмотрению следующего момента обработки событий в компонентах Razor — использованию типа EventCallback<T>
.
Использование EventCallback<T>
Этот тип стоит использовать в том случае, если обработчик события должен получать какие-либо аргументы события. Например, перепишем код Counter с использованием EventCallback<T>
следующим образом:
@page "/counter" <p role="status">Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; [Parameter] public EventCallback<string> OnFullCounter { get; set; } private async Task IncrementCount() { if (currentCount == 10) { await OnFullCounter.InvokeAsync("Это сообщение компонента"); } else currentCount++; } }
Здесь наше событие использует уже тип EventCallback<string>
, то есть обработчик события может принимать в качестве аргумента строку. При вызове обработчика события мы воспользовались второй версией метода InvokeAsync()
:
public System.Threading.Tasks.Task InvokeAsync (object? arg);
В качестве параметров этот метод принимает некий объект — аргумент события. И при вызове обработчика мы это аргумент передаем:
await OnFullCounter.InvokeAsync("Это сообщение компонента");
Теперь перейдем в файл Home.razor
и немного изменим его код:
@page "/" <h1>Hello, world!</h1> @if (showAlert) { <div class="alert alert-danger" role="alert"> @errorMessage </div> } <br /> <Counter OnFullCounter="FullCounter"></Counter> @code{ string errorMessage = "Значение счётчика достигло максимального значения"; bool showAlert = false; private void FullCounter(string message) { if (string.IsNullOrEmpty(message) == false) errorMessage = message; showAlert = true; } }
здесь в обработчике события мы проверяем содержит ли аргумент события какое-либо значение и в зависимости от этого определяем строку сообщения, которая будет показана пользователю:
if (string.IsNullOrEmpty(message) == false) errorMessage = message;
и так как мы передаем в обработчик строку, то теперь работа компонента будет выглядеть следующим образом:
Нетрудно догадаться, что вместо строки мы можем передавать вообще любые объекты.
Итого
Для обработки событий компонентов Razor используются типы EventCallback
и EventCallback<T>
. Типизированный вариант EventCallback
используется в том случае, если обработчик события может получать дополнительные аргументы.