using Microsoft.Extensions.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using Avalonia.Threading; using GSS2.ViewModels; using GSS2.Views; using GSS2.UI.Core; using GSS2.UI.Core.Services; using GSS2.UI.Core.ViewModels; namespace GSS2; public partial class Application : Avalonia.Application { private readonly IServiceProvider _services; private readonly bool _fullscreen; private readonly ILogger _logger; private readonly DependencyInjectionViewLocator _viewLocator; private bool _allShutdownSequencesRunning; public NavigationService Navigation { get; } public Application(IServiceProvider services, bool fullscreen = false) { _services = services; _fullscreen = fullscreen; // Создаём AvaloniaLogSink, который перенаправляет логи из Avalonia в хост var loggerFactory = _services.GetRequiredService(); Avalonia.Logging.Logger.Sink = new AvaloniaLogSink(loggerFactory); // Создаём DependencyInjectionViewLocator _logger = _services.GetRequiredService>(); _viewLocator = _services.GetRequiredService(); Navigation = _services.GetRequiredService(); } public override void Initialize() { AvaloniaXamlLoader.Load(this); // Добавляем наш DependencyInjectionViewLocator в DataTemplates приложения DataTemplates.Add(_viewLocator); } public override void OnFrameworkInitializationCompleted() { // Получаем lifetime хоста var hostLifetime = _services.GetRequiredService(); // Регистрируем обработчик начатия Ctrl+C Console.CancelKeyPress += (_, _) => { _logger.LogInformation("Закрытие приложения вызвано из консоли"); hostLifetime.StopApplication(); }; // Создаём обработчик события закрытия хоста hostLifetime.ApplicationStopped.Register(() => { // Если всё что нужно для закрытия приложения уже вызвано, то ничего не делаем if (_allShutdownSequencesRunning) return; // Иначе это событие вызвано не из интерфейса и графический интерфейс нужно закрыть Dispatcher.UIThread.InvokeShutdown(); _allShutdownSequencesRunning = true; }); // Создаём обработчик события закрытия графического интерфейса Dispatcher.UIThread.ShutdownStarted += (_, _) => { // Если всё что нужно для закрытия приложения уже вызвано, то ничего не делаем if (_allShutdownSequencesRunning) return; // Иначе это событие вызвано из интерфейса и хост нужно закрыть _logger.LogInformation("Закрытие приложения вызвано из интерфейса"); hostLifetime.StopApplication(); _allShutdownSequencesRunning = true; }; // ApplicationLifetime == null, то невозможно определить в какой среде мы запускаемся, // но такого быть не должно if (ApplicationLifetime is null) { _logger.LogCritical("Приложение не может быть полностью инициализировано, ApplicationLifetime == null"); // Я не уверен, будет ли правильно в данном классе вместо выбрасывания исключений, // использовать Environment.Exit, // но если использовать исключения, то их может поймать какой-нибудь обработчик, // а Environment.Exit гарантированно завершит текущий процесс hostLifetime.StopApplication(); Environment.Exit(1); } // Создаём начальный элемент управления и переходим к нему var mainView = new MainView() { DataContext = _services.GetRequiredService() }; // var mainView = new GSS2.UI.Core.Views.CameraView(_services.GetService>()!) // { // DataContext = _services.GetRequiredService() // }; // Создаём главный элемент управления // на основании типа ApplicationLifetime, который зависит от того как мы запустили приложение // StartWithClassicDesktopLifetime IClassicDesktopStyleApplicationLifetime // StartLinuxDrm ISingleViewApplicationLifetime switch (ApplicationLifetime) { case IClassicDesktopStyleApplicationLifetime desktop: _logger.LogInformation("Приложение запускается в классическом режиме"); _logger.LogInformation("Приложение запускается в {} режиме", _fullscreen ? "полноэкранном" : "оконном"); // Создаём главное окно var mainWindow = new MainWindow() { DataContext = new MainWindowViewModel() { WindowDecorations = _fullscreen ? Avalonia.Controls.WindowDecorations.None : Avalonia.Controls.WindowDecorations.Full, Topmost = _fullscreen, WindowState = _fullscreen ? Avalonia.Controls.WindowState.FullScreen : Avalonia.Controls.WindowState.Normal }, }; desktop.MainWindow = mainWindow; // Переключаемся на начальный элемент управления Navigation.NavigateTo(mainView); break; case ISingleViewApplicationLifetime singleView: _logger.LogInformation("Приложение запускается в режиме отображение единой формы"); // Просто устанавливаем главным элементом управления начальный элемент singleView.MainView = mainView; break; default: _logger.LogCritical("Приложение не может быть полностью инициализировано, ApplicationLifetime имеет неизвестный тип, наследованный от: {}", string.Join(", ", ApplicationLifetime.GetType().GetInterfaces().Select(i => i.FullName))); hostLifetime.StopApplication(); Environment.Exit(1); break; } base.OnFrameworkInitializationCompleted(); } }