Перейти к содержанию

Использование и реализация UriLinkAPI и событий UriOpening

Desktop-клиент

Пример реализации пользовательского обработчика ссылок IUriLinkHandler для desktop-клиента:

namespace Tessa.Extensions.Client { // Класс TestUriLinkHandler наследуем от StandardUriLinkHandler, чтобы иметь доступ к стандартной функциональности обработки ссылок. public class TestUriLinkHandler : StandardUriLinkHandler { public override async ValueTask OpenAsync(Uri uri, UriLinkHandlerEventType eventType, CancellationToken cancellationToken = default) { switch (eventType) {

case UriLinkHandlerEventType.HtmlPreview: // Действия в случае возникновения события из предпросмотра html. break; case UriLinkHandlerEventType.HyperLinkLabel: // Действия в случае возникновения события из контрола "Метка". break; // В остальных случаях ссылка обработается стандартным обработчиком. case UriLinkHandlerEventType.FormattedText: case UriLinkHandlerEventType.Default: default: await base.OpenAsync(uri, eventType, cancellationToken); break; } } } }

Регистрация пользовательского обработчика в DI:

namespace Tessa.Extensions.Client { [Registrator] public sealed class TestUriLinkHandlerRegistrator : RegistratorBase { public override void FinalizeRegistration() { this.UnityContainer .RegisterType<IUriLinkHandler, TestUriLinkHandler>(new ContainerControlledLifetimeManager()); } } }

Т.к. в web-клиенте отсутствует механизм DI, для создания необходимой инфраструктуры UriLinkAPI используется глобальная фабрика, которая позволяет переопределить пользовательский обработчик ссылок.

Пример реализации пользовательского обработчика ссылок IUriLinkHandler для web-клиента:

import { IUriLinkHandler } from 'tessa/ui/uriLinks/interfaces'; import { StandardUriLinkHandler } from 'tessa/ui/uriLinks/standardUriLinkHandler'; import { UriLinkHandlerEventType } from 'tessa/ui/uriLinks/uriLinkHandlerEventType';

export class CustomUriLinkHandler extends StandardUriLinkHandler implements IUriLinkHandler { async openAsync(uriString: string, eventType: UriLinkHandlerEventType): Promise<void> { switch (eventType) { case UriLinkHandlerEventType.HtmlPreview: // Действия в случае возникновения события из предпросмотра html. break; case UriLinkHandlerEventType.HyperLinkLabel: // Действия в случае возникновения события из контрола "Метка". break; // В остальных случаях ссылка обработается стандартным обработчиком. case UriLinkHandlerEventType.FormatedText: case UriLinkHandlerEventType.Default: default: await super.openAsync(uriString, eventType); break; } } }

Пример расширения, которое переопределяет обработчик ссылок в глобальной фабрике:

import { ApplicationExtension } from 'tessa'; import { CustomUriLinkHandler } from './customUriLInkHandler'; import { UriLinkDependenciesFactory } from 'tessa/ui/uriLinks/uriLinkDependenciesFactory'; import { IApplicationExtensionContext } from 'tessa/applicationExtensionContext';

export class CustomUriLinkHandlerApplicationExtension extends ApplicationExtension { public initialize(_context: IApplicationExtensionContext): void { UriLinkDependenciesFactory.instance.setCustomUriLinkHandler(new CustomUriLinkHandler()); } }

Регистрация расширения, которое переопределяет обработчик ссылок.

import { ExtensionContainer, ExtensionStage } from 'tessa/extensions';

import { CustomUriLinkHandlerApplicationExtension } from './CustomUriLinkHandlerApplicationExtension';

ExtensionContainer.instance.registerExtension({ extension: CustomUriLinkHandlerApplicationExtension, stage: ExtensionStage.Initialize, singleton: true, order: 1 });

Note

Примеры сильно упрощены, и служат для того, чтобы показать простоту имплементации и необходимые шаги для этого. Вероятнее всего в реальности фабрику зависимостей будет получать объект где-то по цепочке выше, затем создавать зависимости и саму вью-модель, передавая в нее эти зависимости.

Desktop-клиент

Пример вью-модели с имплементацией UriLinkAPI:

public class CustomViewModel : ViewModel<EmptyModel> { private readonly IUriLinkDependenciesFactory uriLinkDependenciesFactory;

// Необходимо получить фабрику зависимостей из DI: public CustomViewModel(IUriLinkDependenciesFactory uriLinkDependenciesFactory) { this.uriLinkDependenciesFactory = uriLinkDependenciesFactory; }

// Some code...

// Метод обработки ссылки. public async ValueTask OnUriOpeningAsync(Uri uri, ICardModel cardModel, CancellationToken cancellationToken = default) { // Получаем зависимости для обработки ссылок. // Если UIContextExecutor не задан, действие будет выполняться в неизвестном контексте (т.е. будет использован UIHelper.UnknownContextExecutorAsync). var uriLinkDependencies = this.uriLinkDependenciesFactory.Create(cardModel.UIContextExecutorAsync);

// Запускаем действие через UiContextExecutorAsync из зависимостей, он выполняет заданный метод в контексте IUIContext, // который устанавливается как текущий контекст и передаётся как параметр в заданный метод. await uriLinkDependencies.UiContextExecutorAsync.Invoke (async (context, ct) => { await uriLinkDependencies.UriLinkHandler.OpenAsync(uri, UriLinkHandlerEventType.Default, ct); }, cancellationToken); }

// Some code...

}

Пример для web-клиента практически аналогичен примеру для desktop-клиента с той разницей, что в данном случае зависимости нужно получать из глобальной фабрики.

export class CustomViewModel { // Зависимости для обработки ссылок. private _uriLinkDependencies: IUriLinkDependencies;

public constructor() { // Создание зависимостей для обработчиков uri из глобальной фабрики. // Если UIContextExecutor не задан, действие будет выполняться в неизвестном контексте (UIContext.unknown). this._uriLinkDependencies = UriLinkDependenciesFactory.instance.create(/*some UIContextExecutor*/); }

// Some code...

// Метод обработки ссылки. public handleLinkAsync = async (href: string): Promise<void> => { this._uriLinkDependencies.uiContextExecutor(async () => { await this._uriLinkDependencies.uriLinkHandler.openAsync( href, UriLinkHandlerEventType.HtmlPreview ); }); };

// Some code... }

Desktop-клиент

Пример desktop-расширения, которое добавляет обработчик события UriOpening в карточках типа “Автомобиль” для всех контролов “Текст с форматированием”.

public sealed class CarUriOpeningUIExtension : CardUIExtension { public override Task Initialized(ICardUIExtensionContext context) { if (context.Card.TypeID != DefaultCardTypes.CarTypeID) // CarTypeID - id типа карточки "Автомобиль" { return Task.CompletedTask; }

this.AddHandlers(context);

return Task.CompletedTask; }

private void AddHandlers(ICardUIExtensionContext context) { // Все контролы "Текст с форматированием". var controls = context.Model.Forms .SelectMany(x => x.Blocks) .SelectMany(x => x.Controls) .Where(x => x is CustomRichTextBoxViewModel).Cast<CustomRichTextBoxViewModel>() .ToList();

foreach (var control in controls) { // Добавление обработчика события. control.RichTextBox.UriOpening += this.LinkHandler; }

return; }

private void LinkHandler(object sender, UriLinkEventArgs e) { if (!e.Cancel) // Если требуется проверить не обработана ли данная ссылка уже в другом событии. { // Do something...

e.Cancel = true; // True, если требуется отменить вызов глобального обработчика после обработчика события UriOpening. e.Handled = true; // Это свойство можно использовать, чтобы обозначить, что событие было обработано. } } }

Пример web-расширения, которое добавляет обработчик события UriOpening в карточках типа “Автомобиль” для контрола “Текст с форматированием” в блоке ‘MainInfo’.

export class CarUriOpeningUIExtension extends CardUIExtension { public initialized(context: ICardUIExtensionContext): void { if (!Guid.equals(context.card.typeId, CarTypeID)) { // CarTypeID - id типа карточки "Автомобиль" return; }

// контрол "Текст с форматированием" в блоке 'MainInfo' const richTextBoxControl = context.model.forms .find(x => x.tabCaption == '$CardTypes_Tabs_Card') ?.blocks.find(x => x.name == 'MainInfo') ?.controls.find(x => x instanceof RichTextBoxViewModel) as RichTextBoxViewModel;

if (richTextBoxControl) { richTextBoxControl.uriOpening.add(this.testUriOpeningHandler); } return; }

private testUriOpeningHandler = (e: UriLinkEventArgs) => { if (!e.cancel) { // Если требуется проверить не обработана ли данная ссылка уже в другом событии.

// Do something...

e.cancel = true; // True, если требуется отменить вызов глобального обработчика после обработчика события UriOpening. e.handled = true; // Это свойство можно использовать, чтобы обозначить, что событие было обработано. } }; }

Back to top