forked from amkovkov/GranuSightSoftware2
1) GSS2.Core: - strip prefixes in GSS2.Core.Analysis.AmineContent namespace class names - add IEnumerable<double>.Variance extension - remake analysis + update database so not needed to store all every file, calibration data also stored in database, also currently capturing images stored in system temporary directory and rewriting every time 2) GSS.UI.Core: AsyncImageRecordViewModel make zoom and pans public 3) GSS: - remove image-storage-clear command - remove ResultsView and ResultsViewModel, results presented in analysis - rework calibration views - add analysis views - add text and number fields editors view - add confirmation view on danger buttons
156 lines
7.7 KiB
C#
156 lines
7.7 KiB
C#
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<Application> _logger;
|
||
private readonly DependencyInjectionViewLocator _viewLocator;
|
||
|
||
private bool _allShutdownSequencesRunning;
|
||
|
||
public NavigationService? Navigation { get; private set; } = null;
|
||
|
||
public Application(IServiceProvider services, bool fullscreen = false)
|
||
{
|
||
_services = services;
|
||
_fullscreen = fullscreen;
|
||
|
||
// Создаём AvaloniaLogSink, который перенаправляет логи из Avalonia в хост
|
||
var loggerFactory = _services.GetRequiredService<ILoggerFactory>();
|
||
Avalonia.Logging.Logger.Sink = new AvaloniaLogSink(loggerFactory);
|
||
|
||
// Создаём DependencyInjectionViewLocator
|
||
_logger = _services.GetRequiredService<ILogger<Application>>();
|
||
_viewLocator = _services.GetRequiredService<DependencyInjectionViewLocator>();
|
||
}
|
||
|
||
public override void Initialize()
|
||
{
|
||
AvaloniaXamlLoader.Load(this);
|
||
// Добавляем наш DependencyInjectionViewLocator в DataTemplates приложения
|
||
DataTemplates.Add(_viewLocator);
|
||
}
|
||
|
||
public override void OnFrameworkInitializationCompleted()
|
||
{
|
||
// Получаем lifetime хоста
|
||
var hostLifetime = _services.GetRequiredService<IHostApplicationLifetime>();
|
||
|
||
// Регистрируем обработчик начатия 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<MainViewModel>()
|
||
};
|
||
// var mainView = new GSS2.UI.Core.Views.CameraView(_services.GetService<ILogger<GSS2.UI.Core.Views.CameraView>>()!)
|
||
// {
|
||
// DataContext = _services.GetRequiredService<GSS2.UI.Core.ViewModels.CameraViewModel>()
|
||
// };
|
||
|
||
// Создаём главный элемент управления
|
||
// на основании типа 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 = _services.GetRequiredService<NavigationService>();
|
||
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();
|
||
}
|
||
}
|