Расширение, обновляющее узел дерева по таймеру
Расширение, обновляющее узел дерева по таймеру¶
Напишем расширение, которое можно будет добавить к узлу дерева “Мои задания”. Для этого после компиляции примера в TessaAdmin выделяем узел “Мои задания” и добавляем наше расширение RefreshMyTasksExtension
.
Расширение позволяет:
-
Обновить текстовое представление узла, чтобы рядом с узлом выводилось количество новых заданий, например: “Мои задания - 5”.
-
Обновить раскрытые сабсеты в дереве, если сейчас не выбран один из узлов в сабсете (иначе узел “схлопнется” и выделение перебросится на один из родительских узлов).
-
Обновить таблицу с заданиями, если сейчас выбран узел “Мои задания” или один из его сабсетов.
Расширение запускает таймер, который обновляет задания только в том случае, если вкладка с рабочим местом “Пользователь” сейчас активна. Если пользователю недоступен узел дерева, с которым связано расширение, то каких-либо действий выполняться не будет.
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
using NLog;
using Tessa.UI.Views;
using Tessa.UI.Views.Extensions;
using Tessa.UI.Views.Workplaces.Tree;
using Unity;
using Unity.Lifetime;
namespace Tessa.Extensions.Client.Views
{
public sealed class RefreshMyTasksExtension :
ITreeItemExtension
{
private DispatcherTimer timer;
private Task asyncTask;
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
private int GetTaskCountAsync(int previousCount)
{
// TODO здесь получаем количество заданий из базы, используем любые зависимости, полученные через конструктор
// например, через ICardRepository выполняем кастомный реквест,
// который в response.Info получает количество заданий:
// this.cardRepository.Request(new CardRequest {RequestType = ...})
Thread.Sleep(500);
return previousCount < 10 ? previousCount + 1 : 0;
}
private static void NotifyTaskArrived(
IWorkplaceViewModel workplace, int taskCount, ITreeItem node, string nodeText)
{
// TODO здесь можно обновить UI, например, мы меняем текст узла, добавляя к нему количество заданий
node.Text = taskCount > 0 ? nodeText + " - " + taskCount : nodeText;
// далее можно обновить раскрытые сабсеты, а также содержимое узла
bool childSelected = false;
ITreeItem currentItem = workplace.CurrentItem;
if (currentItem != node)
{
while (currentItem != null)
{
if (currentItem == node)
{
childSelected = true;
break;
}
currentItem = currentItem.Parent;
}
}
// если не выбран дочерний узел, то рефрешим все узлы
if (!childSelected)
{
node.RefreshNode();
}
// если выбран узел или его дочерний узел, то рефрешим таблицу и перекидываем номер страницы на первый
if (childSelected || node.IsSelected)
{
IViewContext viewContext = workplace.Context.ViewContext;
if (viewContext != null)
{
IViewContext rootContext = viewContext.GetRoot();
IWorkplaceViewComponent viewComponent = rootContext.TryGetViewContainer();
if (viewComponent == null || viewComponent.CurrentPage == 1)
{
rootContext.RefreshView();
}
else
{
viewComponent.CurrentPage = 1;
}
}
}
}
public void Initialized(ITreeItem model)
{
string initialText = model.Text; // локализованный текст узла "Мои задания"
int prevTaskCount = 0;
IWorkplaceViewModel workplace = model.Workplace;
// таймер тикает каждую секунду, за каждый тик отправляется запрос на сервер
this.timer = new DispatcherTimer(DispatcherPriority.ApplicationIdle)
{
Interval = TimeSpan.FromSeconds(10),
};
timer.Tick += (s, e) =>
{
UIHelper.InvokeAsync(
() => this.GetTaskCountAsync(prevTaskCount),
taskCount =>
{
try
{
if (taskCount != prevTaskCount)
{
NotifyTaskArrived(workplace, taskCount, model, initialText);
prevTaskCount = taskCount;
}
}
catch (Exception ex)
{
logger.Log(LogLevel.Error, ex);
// не показываем окно с исключением, чтобы не мешать пользователю
}
});
};
workplace.PropertyChanged += (s, e) =>
{
if (e.PropertyName == "IsActive")
{
if (model.Workplace.IsActive)
{
// вкладка с рабочим местом активирована
timer.Start();
}
else
{
// вкладка с рабочим местом деактивирована
timer.Stop();
}
}
};
if (model.Workplace.IsActive)
{
// вкладка с рабочим местом активна на момент запуска приложения
timer.Start();
}
}
public void Initialize(ITreeItem model)
{
}
public void Clone(ITreeItem source, ITreeItem cloned, ICloneableContext context)
{
}
}
[Registrator]
public sealed class RefreshMyTasksRegistrator : RegistratorBase
{
public override void RegisterUnity()
{
this.UnityContainer
.RegisterType<RefreshMyTasksExtension>(new PerResolveLifetimeManager())
;
}
public override void FinalizeRegistration()
{
if (this.UnityContainer.IsRegistered<IWorkplaceExtensionRegistry>())
{
this.UnityContainer
.Resolve<IWorkplaceExtensionRegistry>()
.Register(typeof(RefreshMyTasksExtension))
;
}
}
}
}