Основа Blazor в AI Core
AI-ориентированная карта reactive-компонентов PoeShared.Blazor, разрешения view, репозитория контента и JS-утилит.
Карта Blazor Foundation
Справочная карта общей Blazor/Razor-инфраструктуры, которая используется в UI приложения EyeAuras, Blazor-окнах, C#-оверлеях, WebView2 host'ах и переиспользуемых UI-контролах.
Для native window hosting используйте windows-subsystems/blazor-windows.md, для screen overlay rendering — osd/screen-overlay.md. Общие принципы PropertyBinder, Rx/ReactiveUI и DynamicData, на которых построены реактивные view-model и отслеживание коллекций, описаны в core/reactivity.md.
Типовые задачи
- Собрать Razor UI, который реагирует на изменения состояния view-model.
- Передать view-model в Razor-компонент через
DataContext. - Отрисовать динамический компонент для объекта модели.
- Зарегистрировать или разрешить Razor view по типу контента.
- Использовать JS-хелперы для фокуса, буфера обмена, CSS, keyboard hooks и dynamic roots.
- Понять, почему компонент перерисовывается или не перерисовывается.
- Добавить в host ресурсы для Blazor или metadata JS-компонентов.
Основные понятия
PoeShared.Blazor— общий базовый слой Blazor.ReactiveComponentBase— низкоуровневая базовая реализация компонента сAnchors,WhenRefresh, sampling refresh-событий, счётчиками рендеров, lifecycle-флагами, логированием и очередью задач after-render.BlazorReactiveComponentBaseдобавляет Blazor-специфичное отслеживание состояния,DataContext,Class,Id,Style, безопасную обёртку над JS runtime и реактивную привязку refresh.BlazorReactiveComponent— обычный базовый класс для Razor-компонентов.BlazorReactiveComponent<TContext>— вариант с типизированнымDataContext.ReactiveSection— предпочтительный способ перерисовывать только часть UI, когда меняются выбранные observables или реактивные коллекции.BlazorContentPresenterотрисовывает динамическое view для объектаContent.IBlazorViewRepositoryразрешает типы view по типу контента и необязательному ключу.IBlazorContentRepositoryхранит дополнительные статические файлы и metadata JS-компонентов, которые используют Blazor host'ы.IJsPoeBlazorUtilsоборачивает типовые операции JavaScript/DOM/WebView2.
Ключевые типы и API
ReactiveComponentBase— базовыйComponentBaseсIReactiveComponent,IDisposable,IAsyncDisposable,AnchorsиWhenRefresh.BlazorReactiveComponentBase— добавляетDataContext, безопасныйIJSRuntime, отслеживание выражений черезTrack(...)иReactiveTrackerList.BlazorReactiveComponent— базовый класс по умолчанию для не-generic Razor-компонентов.BlazorReactiveComponent<TContext>— базовый класс с типизированнымDataContext.ReactiveSection— локальная реактивная граница перерисовки компонента.ReactiveTrackerList— список observables, выраженийWhenAnyValue, списков/кэшей DynamicData и change set'ов, которые могут вызывать обновление section.BlazorContentPresenter— presenter для динамических компонентов, который использует явныйViewTypeили поиск view через repository.IBlazorViewRepository— разрешает зарегистрированные view.IBlazorViewRegistrator— регистрирует view assemblies или отдельные типы view.BlazorViewAttribute— переопределяет тип DataContext, ключ view или помечает view как доступное только для manual registration.AssemblyHasBlazorViewsAttribute— marker assembly, который используется при автоматическом сканировании view.IBlazorContentRepository/BlazorContentRepository— дополнительные статические файлы плюсJSComponentConfigurationStore.IJsPoeBlazorUtils— clipboard, focus, click, scroll, загрузка CSS/JS, dynamic root components, keyboard hooks, хелперы для class/attribute и DOM breadcrumbs.BlazorCommandWrapper— оборачивает команды ReactiveUI для поверхностей команд Blazor/WPF и предоставляет состояние busy/error.BlazorErrorBoundary— error boundary с колбэкомOnError.PoeSharedBlazorRegistrations— модуль регистрации Unity/DI для общих сервисов Blazor.
Подготовить компонент и увидеть обновление
Примеры ниже предназначены для Razor-компонентов внутри настроенного
Blazor-host EyeAuras/PoeShared, где доступны PoeShared.Blazor,
PoeShared.Blazor.Scaffolding, PoeShared.Blazor.Services и ReactiveUI.
Для отслеживания модели она должна отправлять PropertyChanged; обычное
свойство без уведомлений не заставит ReactiveSection обновиться.
Минимальный компонент с собственным состоянием не требует отдельной модели:
@inherits PoeShared.Blazor.BlazorReactiveComponent
<button @onclick="Increment">Добавить</button>
<span>@count</span>
@code {
private int count;
private async Task Increment()
{
count++;
await Refresh("Increment");
}
}
После нажатия число увеличивается. Refresh проходит через инфраструктуру
компонента; для части UI с внешними observables используйте ReactiveSection,
как ниже. Его DebounceTime по умолчанию равен нулю; положительное значение
использует выборку событий (Sample), а не ожидание полной тишины в потоке.
Подписки компонента добавляйте в Anchors и освобождайте вместе с компонентом.
Буфер обмена файлы и DOM
Для законченных примеров IJsPoeBlazorUtils используйте буфер обмена и DOM из Razor. Там показаны копирование и чтение текста, загрузка UTF-8-файла, фокус после отрисовки, выделение, прокрутка и получение элементов под точкой. Также разобраны перегрузки CSS/атрибутов и владение регистрациями обработчиков.
Внедрённый JS-сервис принадлежит host. Освобождаются созданные компонентом регистрации, а не сервис после каждого вызова. Для начальной работы с ElementReference дождитесь отрисовки элемента.
Типовые сценарии
Реактивный Razor-компонент
Для следующего фрагмента создайте MyViewModel с уведомляющим свойством
Status и коллекцией DynamicData Items, передайте экземпляр через
DataContext. Это схема подключения вашей модели, а не отдельный готовый
компонент:
@inherits BlazorReactiveComponent<MyViewModel>
<ReactiveSection Trackers="@(new ReactiveTrackerList()
.With(DataContext.WhenAnyValue(x => x.Status))
.With(DataContext.Items))">
<div>@DataContext.Status</div>
</ReactiveSection>
Используйте ReactiveSection для состояния, которое должно обновлять этот фрагмент. Старые component API Track(...) / TrackState(...) всё ещё существуют, но помечены как заменённые реактивными секциями.
Динамическое view для модели
Здесь currentModel — поле компонента с вашим объектом модели. До первого
показа зарегистрируйте соответствующее view в host:
<BlazorContentPresenter Content="@currentModel" />
Presenter разрешает view через IBlazorViewRepository по типу модели и ключу.
При отсутствии соответствия repository возвращает null; поздняя регистрация
сама по себе не гарантирует обновления уже показанного presenter. Если найденное view наследуется от BlazorReactiveComponent, presenter передаёт модель в DataContext.
Регистрация типа view
В инициализации модуля получите IBlazorViewRegistrator через DI;
MyDetailsView и MyModel ниже — ваши типы:
registrator.RegisterViewType(typeof(MyDetailsView), typeof(MyModel), "Details");
Автоматическое сканирование ожидает, что assembly помечена AssemblyHasBlazorViewsAttribute. View также может наследоваться от BlazorReactiveComponent<TContext>, и тогда repository сможет вывести тип контента автоматически.
Использование JS utilities
@inject IJsPoeBlazorUtils JsUtils
<input id="search-box" />
<button @onclick="FocusSearch">Focus</button>
@code {
private async Task FocusSearch()
{
await JsUtils.FocusElementById("search-box");
}
}
После нажатия Focus фокус переходит в поле search-box. Вызывайте это
после появления элемента в DOM. Сервис должен быть зарегистрирован в host.
Всегда ожидайте JS-вызовы через await. Безопасная обёртка над JS runtime логирует ошибки JS invocation и сообщает о пропущенных await через dispatcher компонента.
Контекст host'а и runtime
- UI приложения и WebView2 host'ы регистрируют общие сервисы Blazor через
PoeSharedBlazorRegistrations. - Razor-компоненты используют Blazor
[Inject],[Parameter], lifecycle methods иDataContext; глобальные переменные верхнего уровня скрипта не являются глобалами компонента. - Blazor-окна используют эту основу, но дополнительно работают с native window ownership и WebView2 hosting.
- C#-оверлеи используют ту же основу, но настраиваются через aura overlay settings.
- Blazor в браузере не имеет доступа ко всем сервисам native host'а; например, контроллеры окон host'а — это понятие native host'а.
Что предпочитать
- Предпочитайте
BlazorReactiveComponent<TContext>, если компонент рассчитан на конкретный тип view-model. - Предпочитайте
ReactiveSectionи явные элементыReactiveTrackerList, если нужен точный контроль над перерисовкой. - Предпочитайте
BlazorContentPresenterи регистрацию view для динамического UI. - Предпочитайте
IJsPoeBlazorUtilsдля типовых операций с DOM, clipboard, focus, CSS и JS. - Предпочитайте
Anchorsдля подписок компонента и других ресурсов, которыми владеет компонент. - Если задача связана с открытием, размерами, перемещением или управлением native Blazor-окном, переходите в
windows-subsystems/blazor-windows.md.
Чего избегать
- Не предполагаете, что обычные Blazor-компоненты могут обращаться к top-level member'ам скрипта вроде
Log,VariablesилиcancellationToken. - Не делайте широкие refresh всего компонента, если небольшая
ReactiveSectionможет отслеживать нужное состояние напрямую. - Не используйте устаревшие
Track(...)/TrackState(...)в новых компонентах. - Не регистрируйте view только по соглашению, если для одной модели существует несколько view; используйте ключ или явную регистрацию.
- Не используйте fire-and-forget для JS interop; вызывайте через
awaitи обрабатывайте исключения. - Не добавляйте JS-компоненты после того, как страница уже загружена, если не уверены, что metadata компонента доступна на стороне клиента.
Ключевые сущности для поиска
ReactiveComponentBaseBlazorReactiveComponentBaseBlazorReactiveComponentBlazorReactiveComponent<TContext>ReactiveSectionReactiveTrackerListBlazorContentPresenterIBlazorViewRepositoryIBlazorViewRegistratorBlazorViewAttributeAssemblyHasBlazorViewsAttributeIBlazorContentRepositoryBlazorContentRepositoryIJsPoeBlazorUtilsBlazorCommandWrapperBlazorErrorBoundaryPoeSharedBlazorRegistrations
По каким словам искать
- Blazor foundation
- Razor component
- reactive component
- BlazorReactiveComponent
- ReactiveSection
- ReactiveTrackerList
- DataContext
- dynamic view
- view repository
- BlazorContentPresenter
- JS interop
- IJsPoeBlazorUtils
- WebView2 Blazor
- component refresh
- component anchors