/
kochkatech
/
Queue
Обзор
Документация
Войти
/
kochkatech
/
Queue
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
dev
src/Queue.Display/App.xaml.cs
123 строки
5 KB
kochkareal
feat: вкладка "Экраны" в Admin — запуск/управление табло и АРМ оператора
27 июл 2026, 21:26
27 июл 2026, 21:26
62e41f9
Код
Авторство
О чём код?
using System; using System.IO; using System.IO.Pipes; using System.Linq; using System.Threading.Tasks; // UseWindowsForms=true (нужен для Screen API в BoardWindow) добавляет неявную ссылку на // System.Windows.Forms, где тоже есть Application — уточняем явно, какой имеется в виду. using Application = System.Windows.Application; using StartupEventArgs = System.Windows.StartupEventArgs; using Queue.Display.Services; using Queue.Display.ViewModels; using Queue.Display.Views; namespace Queue.Display; public partial class App : Application { // async void оправдан здесь: OnStartup — точка входа WPF, вызывающего кода, который мог бы // дождаться завершения, нет. Все ошибки внутри перехватываются на месте (см. ShowBoardAsync). // --windowed — Queue.Admin запускает табло этим флагом (вкладка "Экраны"), чтобы окно // открылось обычным (перетаскиваемым на нужный монитор), а не сразу киоском. Без флага — // прежнее поведение (для самостоятельного запуска на выделенном ТВ/мониторе). private bool _startWindowed; protected override async void OnStartup(StartupEventArgs e) { base.OnStartup(e); _startWindowed = e.Args.Contains("--windowed"); var apiClient = new QueueApiClient(); var settings = DisplaySettings.Load(); if (!string.IsNullOrWhiteSpace(settings.ServerAddress)) { // Адрес уже сохранён (табло настраивали ранее) — сразу подключаемся, без экрана ввода. apiClient.Configure(settings.ServerAddress); await ShowBoardAsync(apiClient); return; } ShowConnectWindow(apiClient, settings.ServerAddress ?? "http://localhost:5080"); } private void ShowConnectWindow(QueueApiClient apiClient, string initialAddress) { var connectViewModel = new ConnectViewModel(apiClient, initialAddress); var connectWindow = new ConnectWindow { DataContext = connectViewModel }; connectViewModel.Connected += (_, _) => { // ConnectViewModel уже поднял соединение SignalR при успешном подключении. ShowBoardWindow(apiClient); connectWindow.Close(); }; connectWindow.Show(); } private async Task ShowBoardAsync(QueueApiClient apiClient) { try { await apiClient.ConnectHubAsync(); } catch { // Живые обновления недоступны — табло продолжит работать по резервному опросу (см. BoardViewModel). } ShowBoardWindow(apiClient); } private void ShowBoardWindow(QueueApiClient apiClient) { var boardViewModel = new BoardViewModel(apiClient); var boardWindow = new BoardWindow(_startWindowed) { DataContext = boardViewModel }; if (_startWindowed) { // Канал слушаем только когда запущены из Queue.Admin — для самостоятельного // запуска на выделенном ТВ/мониторе он не нужен и не открывается. var pipeServer = new KioskControlPipeServer(Environment.ProcessId); pipeServer.KioskModeRequested += isKiosk => Dispatcher.Invoke(() => { if (isKiosk) { boardWindow.EnterKioskMode(); } else { boardWindow.EnterWindowedMode(); } }); boardWindow.Closed += (_, _) => pipeServer.Dispose(); // Обратное уведомление в Admin — в т.ч. на случай, если пользователь сам нажал // Escape на табло, а не через кнопку в Admin: без этого список экранов показывал бы // устаревший режим (см. Queue.Admin/Services/ScreenStatusListener.cs). boardWindow.ModeChanged += isKiosk => _ = NotifyAdminAsync(isKiosk); } boardWindow.Show(); } private static async Task NotifyAdminAsync(bool isKiosk) { try { var pipeName = $"queue-admin-notify-{Environment.ProcessId}"; using var client = new NamedPipeClientStream(".", pipeName, PipeDirection.Out); await client.ConnectAsync(1000); await using var writer = new StreamWriter(client) { AutoFlush = true }; await writer.WriteLineAsync(isKiosk ? "kiosk" : "windowed"); } catch (Exception ex) when (ex is IOException or TimeoutException or OperationCanceledException) { // Admin мог уже закрыть слушатель (например, само окно табло закрывается) — // не критично, это лишь необязательное уведомление для UI. } } }