Работа с файлами посредством контрола "Представление"
Работа с файлами посредством контрола “Представление”¶
С помощью расширений можно модифицировать контрол Представление аналогично расширению типа карточки “Список файлов в представлении”.
Проведем декомпозицию данной задачи на подзадачи:
-
Создание представления на клиенте:
Рассмотрим процесс инициализации контрола представления. Инициализация происходит после выполнения расширений
ICardUIExtension.Initializing
и до выполнения расширенияICardUIExtension.Initialized
по средствам стратегии, реализующей интерфейс IViewCardControlInitializationStrategy. Получение данных строк представления происходит по средством объекта, реализующего интерфейсIDataProvider
. В процессе исполнения стандартной стратегииViewCardControlInitializationStrategy
происходит инициализация провайдера данных представления, колонок, кнопок в верхней части контрола. Стандартная стратегия не будет выполнена, если в базе данных будет отсутствовать представление с алиасом, указанным в настройках контрола в TessaAdmin.
Для выполнения данной задачи мы можем получить метаданные из представления, созданного в TessaAdmin (текст sql запроса в этом представлении не важен) и задать кастомный провайдер данных после исполнения стратегии. Сделать это необходимо до выполнения ICardUIExtension.Initialized
, так как первое обновление представления может происходить при инициализации открытой вкладки. Для выполнения данной модификации добавим функцию в список функций CardModel.ControlInitializers
, выполняемый сразу после инициализации каждого контрола:
public override Task Initializing(ICardUIExtensionContext context)
{
context.Model.ControlInitializers.Add((control, m, r, ct) =>
{
if (control is CardViewControlViewModel viewControl)
{
if (viewControl.Name == "YourViewControlAlias")
{
viewControl.DataProvider = new YourDataProvider();
}
}
return new ValueTask();
});
return Task.CompletedTask;
}
Если требуется создавать метаданные программно, то нам необходимо создать наследника ViewCardControlInitializationStrategy
, в которой метаданные будут заданы программно и инициализация представление будет инициализировано на основе программно созданных метаданных. Нам достаточно переопределить методы инициализации метаданых и провайдера данных:
public class YourViewCardControlInitializationStrategy : ViewCardControlInitializationStrategy
{
public YourViewCardControlInitializationStrategy(IViewService viewService,
CreateMenuContextFunc createMenuContextFunc,
IViewCardControlContentItemsFactory contentItemsFactory)
: base(viewService, createMenuContextFunc, contentItemsFactory)
{ }
/// <summary>
/// Вызывается для инициализации метаданных в модели, заданной в контексте инициализации
/// </summary>
/// <param name="context">Контекст инициализации</param>
public override ValueTask InitializeMatadataAsync(CardViewControlInitializationContext context)
{
context.ControlViewModel.ViewMetadata = YourCreateMetadataFunc();
return new ValueTask();
}
/// <summary>
/// Вызывается для инициализации провадера данных в модели, заданной в контексте инициализации
/// </summary>
/// <param name="context">Контекст инициализации</param>
public override ValueTask InitializeDataProviderAsync(CardViewControlInitializationContext context)
{
context.ControlViewModel.DataProvider = new YourDataProvider();
return new ValueTask();
}
}
Затем нам необходимо исполнить данную стратегию. Мы можем сделать это в CardModel.ControlInitializers
, используемом в примере ранее или в ICardUIExtension.Initialized
, но, в этом случае если представление расположено на открытой вкладке, то оно не будет инициализировано на вкладке и будет необходимо самостоятельно инициализировать представление на вкладке, вызвав метод CardViewControlViewModel.InitializeOnTabAsync
. Кастомный провайдер данных необходимо зарегистрировать в Unity контейнере без указания интерфейса.
[Registrator]
public sealed class Registrator : RegistratorBase
{
public override void RegisterUnity()
{
this.UnityContainer.RegisterType<ourViewCardControlInitializationStrategy>(new ContainerControlledLifetimeManager());
}
}
public sealed class YourUIExtension : CardUIExtension
{
private readonly IViewCardControlInitializationStrategy initializationStrategy;
// Получаем YourViewCardControlInitializationStrategy из Unity контенера указывая конкретный класс.
// Если указать в параметре IViewCardControlInitializationStrategy, то вернется стандартная стратегия инициализации.
public YourUIExtension(YourViewCardControlInitializationStrategy initializationStrategy)
{
this.initializationStrategy = initializationStrategy ?? throw new ArgumentNullException(nameof(initializationStrategy));
}
// Первый способ применении кастомной стратегии инициализации представления.
public override Task Initializing(ICardUIExtensionContext context)
{
context.Model.ControlInitializers.Add(async (control, m, r, ct) =>
{
if (control is CardViewControlViewModel viewControl)
{
if (viewControl.Name == "YourViewControlAlias")
{
viewControl.InitializeStrategyAsync(initializationStrategy, true, ct);
}
}
});
return Task.CompletedTask;
}
// Второй способ применении кастомной стратегии инициализации представления.
public override async Task Initialized(ICardUIExtensionContext context)
{
if (!context.Model.Controls.TryGet("YourViewControlAlias", out var controlViewModel))
{
throw new ArgumentException($"Control ViewModel with Name='{"YourViewControlAlias"}' not found.");
}
var viewControlViewModel = controlViewModel as CardViewControlViewModel;
await viewControlViewModel.InitializeStrategyAsync(initializationStrategy, true, context.CancellationToken);
// инициализируем представление на вкладке.
await viewControlViewModel.InitializeOnTabAsync();
}
}
Tip
Пример стратегии инициализации модели представления доступен в файле FilesViewCardControlInitializationStrategy.cs
- Модифицировать строки представления:
Если необходимо модифицировать строку один раз при ее создании, то мы можем задать CardViewControlViewModel.CreateRowFunc
. Данная функция позволяет с помощью расширений создавать каждую строку и модифицировать ее. Например, добавить тултип или изменить цвет. Для добавления тэгов необходимо добавить функцию CardViewControlViewModel.ModifyRowActions
, которая исполняется после инициализации строки ячейками. Тэг это опционально кликабельная иконка с опициональным тултипом, например, в представлении “История заданий” используются тэги с иконкой скрепки для открытия сателлита задания. Рекомендуется использовать IconViewModel
.
Tip
Пример использования CardViewControlViewModel.ModifyRowActions
доступен в файле WfTaskHistoryViewUIExtension.cs
.
Если строка представления должна изменять цвет, тэг или тултип без обновления представления, то необходимо создать наследника ViewControlRowViewModel, который будет подписан на события, приводящие к изменениям свойств строки и будет изменять свои свойства при их возникновении. Рекомендуется использовать слабые ссылки, чтобы избежать утечки памяти.
Tip
Пример наследника ViewControlRowViewModel
доступен в файле TableFileRowViewModel.cs
.