feat: move mainwindow to core and add NavigationService

This commit is contained in:
2026-02-19 13:13:57 +03:00
parent 9cf8d7c909
commit 35e2397a29
8 changed files with 124 additions and 56 deletions
+38 -21
View File
@@ -5,6 +5,9 @@ using Avalonia.Threading;
using GSS2.Test.ViewModels;
using GSS2.Test.Views;
using GSS2.UI.Core;
using GSS2.UI.Core.Services;
using GSS2.UI.Core.ViewModels;
namespace GSS2.Test;
@@ -20,30 +23,44 @@ public partial class App : Application
if (ApplicationLifetime is null)
throw new InvalidOperationException("Application framework initialization cannot be fulfilled, ApplicationLifetime is null");
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
Console.WriteLine("Application running in classic style");
desktop.Startup += (_, _) => Program.ApplicationHost.RunAsync();
desktop.Exit += (_, _) => Program.ApplicationHost.StopAsync();
var loggerFactory = Program.ApplicationHost.Services.GetRequiredService<ILoggerFactory>();
var navigationService = Program.ApplicationHost.Services.GetRequiredService<NavigationService>();
desktop.MainWindow = new MainWindow()
{
DataContext = Program.ApplicationHost.Services.GetRequiredService<MainWindowViewModel>()
};
Program.ShutdownRequested += (_, _) => Dispatcher.UIThread.Invoke(() => desktop.MainWindow.Close());
}
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleView)
switch (ApplicationLifetime)
{
Console.WriteLine("Application running in single view style");
var loggerFactory = Program.ApplicationHost.Services.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<MainView>();
singleView.MainView = new MainView(logger)
{
DataContext = Program.ApplicationHost.Services.GetRequiredService<MainViewModel>()
};
case IClassicDesktopStyleApplicationLifetime desktop:
Console.WriteLine("Application running in classic style");
desktop.Startup += (_, _) => Program.ApplicationHost.RunAsync();
desktop.Exit += (_, _) => Program.ApplicationHost.StopAsync();
var mainWindowViewModelLogger = loggerFactory.CreateLogger<MainWindowViewModel>();
var mainWindow = new MainWindow()
{
DataContext = new MainWindowViewModel(mainWindowViewModelLogger)
};
desktop.MainWindow = mainWindow;
Program.ShutdownRequested += (_, _) => Dispatcher.UIThread.Invoke(() => desktop.MainWindow?.Close());
break;
case ISingleViewApplicationLifetime singleView:
Console.WriteLine("Application running in single view style");
break;
default:
throw new InvalidOperationException($"Application framework initialization cannot be fulfilled, ApplicationLifetime has unknown type inherited from: {string.Join(", ", ApplicationLifetime.GetType().GetInterfaces().Select(i => i.FullName))}");
}
else
throw new InvalidOperationException($"Application framework initialization cannot be fulfilled, ApplicationLifetime has unknown type inherited from: {string.Join(", ", ApplicationLifetime.GetType().GetInterfaces().Select(i => i.FullName))}");
var mainViewLogger = loggerFactory.CreateLogger<MainView>();
var mainView = new MainView(mainViewLogger)
{
DataContext = Program.ApplicationHost.Services.GetRequiredService<MainViewModel>()
};
navigationService.NavigateTo(mainView);
base.OnFrameworkInitializationCompleted();
}
}
+4
View File
@@ -2,6 +2,9 @@ using GSS2.UI.Core.Views;
using GSS2.UI.Core.ViewModels;
using GSS2.Test.Views;
using GSS2.Test.ViewModels;
using GSS2.UI.Core.Services;
using Avalonia;
namespace GSS2.Test;
@@ -9,6 +12,7 @@ public static class DependencyInjectionHelper
{
public static IServiceCollection AddViewsAndModels(this IServiceCollection services) =>
services
.AddSingleton<NavigationService>((_) => new NavigationService(Application.Current?.ApplicationLifetime))
.AddSingleton<MainWindowViewModel>()
.AddSingleton<MainView>()
.AddSingleton<MainViewModel>()
-11
View File
@@ -1,11 +0,0 @@
using Avalonia.Controls;
namespace GSS2.Test;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
+4 -1
View File
@@ -11,6 +11,7 @@ public partial class MainViewModel : ViewModelBase
private readonly ILogger<MainViewModel> _logger;
private readonly CameraService _cameraService;
private readonly IlluminatorService _illuminatorService;
[ObservableProperty] private CameraViewModel _cameraViewModel;
[ObservableProperty] private ResourcesViewModel _resourcesViewModel;
[ObservableProperty] private IlluminatorControllerViewModel _illuminatorControllerViewModel;
@@ -28,6 +29,8 @@ public partial class MainViewModel : ViewModelBase
public MainViewModel(ILogger<MainViewModel> logger, CameraViewModel cameraViewModel, ResourcesViewModel resourcesViewModel, IlluminatorControllerViewModel illuminatorControllerViewModel, CameraService cameraService, IlluminatorService illuminatorService)
{
_logger = logger;
_logger.LogInformation("Initialization");
_cameraService = cameraService;
_illuminatorService = illuminatorService;
CameraViewModel = cameraViewModel;
@@ -53,6 +56,6 @@ public partial class MainViewModel : ViewModelBase
ButtonUpClick = new RelayCommand(() => CurrentIndex--);
ButtonDownClick = new RelayCommand(() => CurrentIndex++);
_logger.LogInformation("{} initialized", nameof(MainViewModel));
_logger.LogInformation("Initialized");
}
}
@@ -1,20 +0,0 @@
using CommunityToolkit.Mvvm.ComponentModel;
using GSS2.UI.Core.ViewModels;
namespace GSS2.Test.ViewModels;
public partial class MainWindowViewModel : ViewModelBase
{
[ObservableProperty] private string _title;
[ObservableProperty] private MainViewModel _mainViewModel;
private readonly ILogger<MainWindowViewModel> _logger;
public MainWindowViewModel(ILogger<MainWindowViewModel> logger, MainViewModel mainViewModel)
{
_logger = logger;
MainViewModel = mainViewModel;
Title = "GSS2.Test";
_logger.LogInformation("{} initialized", nameof(MainWindowViewModel));
}
}
@@ -1,13 +1,13 @@
<Window
x:Class="GSS2.Test.MainWindow"
x:Class="GSS2.UI.Core.MainWindow"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:GSS2.Test.ViewModels"
xmlns:vm="using:GSS2.UI.Core.ViewModels"
Title="{Binding Title}"
x:DataType="vm:MainWindowViewModel">
<ContentControl Content="{Binding MainViewModel}" />
<ContentControl x:Name="MainContent" />
</Window>
+16
View File
@@ -0,0 +1,16 @@
using Avalonia.Controls;
namespace GSS2.UI.Core;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void SetControl(UserControl control)
{
MainContent.Content = control;
}
}
+59
View File
@@ -0,0 +1,59 @@
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
namespace GSS2.UI.Core.Services;
public class NavigationService
{
private readonly Stack<UserControl> _navigateControls = new Stack<UserControl>();
private readonly IApplicationLifetime? _applicationLifetime;
public NavigationService(IApplicationLifetime? applicationLifetime)
{
_applicationLifetime = applicationLifetime;
}
public void NavigateTo(UserControl control)
{
_navigateControls.Push(control);
switch (_applicationLifetime)
{
case IClassicDesktopStyleApplicationLifetime desktop
when desktop.MainWindow is MainWindow mainWindow:
mainWindow.SetControl(control);
break;
case ISingleViewApplicationLifetime singleView:
singleView.MainView = control;
break;
}
}
public void NavigateBack()
{
if (_navigateControls.Count <= 1)
return;
var lastControl = _navigateControls.Pop();
var control = _navigateControls.Peek();
switch (_applicationLifetime)
{
case IClassicDesktopStyleApplicationLifetime desktop
when desktop.MainWindow is MainWindow mainWindow:
mainWindow.SetControl(control);
break;
case ISingleViewApplicationLifetime singleView:
singleView.MainView = control;
break;
}
if (lastControl is IDisposable disposable)
disposable.Dispose();
}
}