diff --git a/StabilityMatrix.Avalonia/App.axaml b/StabilityMatrix.Avalonia/App.axaml new file mode 100644 index 00000000..822dc1e9 --- /dev/null +++ b/StabilityMatrix.Avalonia/App.axaml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/StabilityMatrix.Avalonia/App.axaml.cs b/StabilityMatrix.Avalonia/App.axaml.cs new file mode 100644 index 00000000..803687e4 --- /dev/null +++ b/StabilityMatrix.Avalonia/App.axaml.cs @@ -0,0 +1,64 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; +using Avalonia.Styling; +using Microsoft.Extensions.DependencyInjection; +using StabilityMatrix.Avalonia.ViewModels; +using StabilityMatrix.Avalonia.Views; + +namespace StabilityMatrix.Avalonia; + +public partial class App : Application +{ + public static IServiceProvider Services { get; set; } = null!; + + + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + + // Set design theme + if (Design.IsDesignMode) + { + RequestedThemeVariant = ThemeVariant.Dark; + } + } + + public override void OnFrameworkInitializationCompleted() + { + ConfigureServiceProvider(); + + var mainViewModel = Services.GetRequiredService(); + + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + desktop.MainWindow = new MainWindow + { + DataContext = mainViewModel + }; + } + + base.OnFrameworkInitializationCompleted(); + } + + private static void ConfigureServiceProvider() + { + var services = ConfigureServices(); + Services = services.BuildServiceProvider(); + } + + private static IServiceCollection ConfigureServices() + { + var services = new ServiceCollection(); + + services.AddSingleton(); + services.AddSingleton(); + + services.AddTransient(); + + return services; + } +} diff --git a/StabilityMatrix.Avalonia/Assets/avalonia-logo.ico b/StabilityMatrix.Avalonia/Assets/avalonia-logo.ico new file mode 100644 index 00000000..da8d49ff Binary files /dev/null and b/StabilityMatrix.Avalonia/Assets/avalonia-logo.ico differ diff --git a/StabilityMatrix.Avalonia/Program.cs b/StabilityMatrix.Avalonia/Program.cs new file mode 100644 index 00000000..35ce2c2a --- /dev/null +++ b/StabilityMatrix.Avalonia/Program.cs @@ -0,0 +1,24 @@ +using Avalonia; +using System; +using System.Diagnostics.CodeAnalysis; + +namespace StabilityMatrix.Avalonia; + +[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class Program +{ + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + [STAThread] + public static void Main(string[] args) => BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .LogToTrace(); +} diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj new file mode 100644 index 00000000..25f7c08c --- /dev/null +++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj @@ -0,0 +1,28 @@ + + + WinExe + net7.0 + enable + true + app.manifest + true + + + + + + + + + + + + + + + + + + + + diff --git a/StabilityMatrix.Avalonia/ViewLocator.cs b/StabilityMatrix.Avalonia/ViewLocator.cs new file mode 100644 index 00000000..1e98f2c5 --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewLocator.cs @@ -0,0 +1,34 @@ +using System; +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using StabilityMatrix.Avalonia.ViewModels; + +namespace StabilityMatrix.Avalonia; + +public class ViewLocator : IDataTemplate +{ + public Control Build(object? data) + { + if (data is null) throw new ArgumentNullException(nameof(data)); + + var name = data.GetType().FullName!.Replace("ViewModel", "View"); + var type = Type.GetType(name); + + // Get from DI + if (type is not null) + { + var view = App.Services.GetService(type); + if (view is not null) + { + return (Control) view; + } + } + + return new TextBlock {Text = "Not Found: " + name}; + } + + public bool Match(object? data) + { + return data is ViewModelBase; + } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/LaunchPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/LaunchPageViewModel.cs new file mode 100644 index 00000000..4224216d --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/LaunchPageViewModel.cs @@ -0,0 +1,19 @@ +using System; + +namespace StabilityMatrix.Avalonia.ViewModels; + +public partial class LaunchPageViewModel : PageViewModelBase +{ + /// + /// The Title of this page + /// + public string Title => "Welcome to our Wizard-Sample."; + + /// + /// The content of this page + /// + public string Message => "Press \"Next\" to register yourself."; + + public override bool CanNavigateNext { get; protected set; } + public override bool CanNavigatePrevious { get; protected set; } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs new file mode 100644 index 00000000..dd4de726 --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using Avalonia.Controls; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace StabilityMatrix.Avalonia.ViewModels; + +public partial class MainWindowViewModel : ViewModelBase +{ + public string Greeting => "Welcome to Avalonia!"; + + [ObservableProperty] + private PageViewModelBase? currentPage; + + public List Pages { get; } = new(); + + public MainWindowViewModel(LaunchPageViewModel launchPageViewModel) + { + Pages.Add(launchPageViewModel); + CurrentPage = Pages[0]; + } + + public MainWindowViewModel() + { + if (!Design.IsDesignMode) + { + throw new InvalidOperationException("Default Constructor is only for design-time."); + } + Pages.Add(new LaunchPageViewModel()); + CurrentPage = Pages[0]; + } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/PageViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/PageViewModelBase.cs new file mode 100644 index 00000000..896069c8 --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/PageViewModelBase.cs @@ -0,0 +1,17 @@ +namespace StabilityMatrix.Avalonia.ViewModels; + +/// +/// An abstract class for enabling page navigation. +/// +public abstract class PageViewModelBase : ViewModelBase +{ + /// + /// Gets if the user can navigate to the next page + /// + public abstract bool CanNavigateNext { get; protected set; } + + /// + /// Gets if the user can navigate to the previous page + /// + public abstract bool CanNavigatePrevious { get; protected set; } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/SecondPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/SecondPageViewModel.cs new file mode 100644 index 00000000..97bab672 --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/SecondPageViewModel.cs @@ -0,0 +1,27 @@ +using System; +using System.ComponentModel.DataAnnotations; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace StabilityMatrix.Avalonia.ViewModels; + +/// +/// This is our ViewModel for the second page +/// +partial class SecondPageViewModel : PageViewModelBase +{ + public SecondPageViewModel() + { + } + + [Required] + [EmailAddress] + [ObservableProperty] + private string? mailAddress; + + [Required] + [ObservableProperty] + private string? password; + + public override bool CanNavigateNext { get; protected set; } = true; + public override bool CanNavigatePrevious { get; protected set; } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/ViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/ViewModelBase.cs new file mode 100644 index 00000000..1828b85d --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/ViewModelBase.cs @@ -0,0 +1,7 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace StabilityMatrix.Avalonia.ViewModels; + +public class ViewModelBase : ObservableValidator +{ +} diff --git a/StabilityMatrix.Avalonia/Views/LaunchPageView.axaml b/StabilityMatrix.Avalonia/Views/LaunchPageView.axaml new file mode 100644 index 00000000..e0f45b54 --- /dev/null +++ b/StabilityMatrix.Avalonia/Views/LaunchPageView.axaml @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +