diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index df9cf82..a35efa0 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -25,9 +25,9 @@ jobs: with: name: Linux-Artifact path: | - ./src/bin/x64/Release/net7.0/linux-x64/publish/*.bin - ./src/bin/x64/Release/net7.0/linux-x64/publish/*.so - ./src/bin/x64/Release/net7.0/linux-x64/publish/*.png + ./src/bin/Release/net7.0/linux-x64/publish/*.bin + ./src/bin/Release/net7.0/linux-x64/publish/*.so + ./src/bin/Release/net7.0/linux-x64/publish/*.png build-on-windows: runs-on: windows-latest steps: @@ -42,9 +42,9 @@ jobs: with: name: Windows-Artifact path: | - .\src\bin\x64\Release\net7.0\win-x64\publish\*.exe - .\src\bin\x64\Release\net7.0\win-x64\publish\*.dll - .\src\bin\x64\Release\net7.0\win-x64\publish\*.png + .\src\bin\Release\net7.0\win-x64\publish\*.exe + .\src\bin\Release\net7.0\win-x64\publish\*.dll + .\src\bin\Release\net7.0\win-x64\publish\*.png build-on-macos: runs-on: macos-latest steps: @@ -57,9 +57,9 @@ jobs: run: | sudo chmod +x ./test.command ./test.command - cd ./src/bin/x64/Release/net7.0/osx-x64/publish + cd ./src/bin/Release/net7.0/osx-x64/publish zip -r -0 macOS-Artifact.zip *.app - mv *.zip ../../../../../../../. + mv *.zip ../../../../../../. - uses: actions/upload-artifact@v2 with: name: macOS-Artifact diff --git a/AvaloniaCoreRTDemo.sln b/AvaloniaCoreRTDemo.sln index 33fc22d..29985ad 100644 --- a/AvaloniaCoreRTDemo.sln +++ b/AvaloniaCoreRTDemo.sln @@ -7,14 +7,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaCoreRTDemo", "src\A EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {41A52A04-F7D8-4981-9546-DB020E54851D}.Debug|x64.ActiveCfg = Debug|x64 - {41A52A04-F7D8-4981-9546-DB020E54851D}.Debug|x64.Build.0 = Debug|x64 - {41A52A04-F7D8-4981-9546-DB020E54851D}.Release|x64.ActiveCfg = Release|x64 - {41A52A04-F7D8-4981-9546-DB020E54851D}.Release|x64.Build.0 = Release|x64 + {41A52A04-F7D8-4981-9546-DB020E54851D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {41A52A04-F7D8-4981-9546-DB020E54851D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {41A52A04-F7D8-4981-9546-DB020E54851D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {41A52A04-F7D8-4981-9546-DB020E54851D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/README.md b/README.md index d284705..f349479 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This project is tested only under Windows, and this readme assumes you are using * Any supported 64-bit edition of Windows. NativeAOT requires 64-bit Windows and produces only 64-bit Windows apps. * Visual Studio. VS 2022 Community is free for personal use. Get if from [here](https://visualstudio.microsoft.com). When installing Visual Studio, select *.NET desktop development* and *Desktop development with C++* workloads. To generate native code, NativeAOT requires the native C++ toolchain and Windows SDK. This configuration ensures you have them. -* .Net 6.0 SDK. Download it from [here](https://dotnet.microsoft.com/download/dotnet/6.0). Note: Make sure that you download and install the *SDK*. The runtime is not enough for building apps. +* .Net 7.0 SDK. Download it from [here](https://dotnet.microsoft.com/download/dotnet/7.0). Note: Make sure that you download and install the *SDK*. The runtime is not enough for building apps. * Git. Install [Git for Windows](https://git-scm.com/download/win). ## Getting started @@ -34,8 +34,6 @@ We are ready - In your terminal, navigate to `src\bin\Release\net6.0\win-x64\pub Feel free to use this sample as a base for your projects. -When developing, keep in mind that Avalonia uses Reflection extensively. NativeAOT, being an AOT compiler, needs your help to get reflection right. Refer to `rd.xml` file in the solution. In it, you describe all assemblies and types which your app would potentially reflect over. For more information, see [Reflection in AOT mode](https://github.com/dotnet/runtimelab/blob/feature/NativeAOT/docs/using-nativeaot/reflection-in-aot-mode.md) - This project is configured to help you debug issues with publishing. Before publishing, check the CSPROJ file and modify the various Ilc* properties according to [Optimizing programs targeting Native AOT](https://github.com/dotnet/runtimelab/blob/feature/NativeAOT/docs/using-nativeaot/optimizing.md) document. ## Artifact test diff --git a/src/App.axaml b/src/App.axaml index 65e3c87..bc3aa7a 100644 --- a/src/App.axaml +++ b/src/App.axaml @@ -1,10 +1,17 @@ + xmlns:viewModels1="clr-namespace:AvaloniaCoreRTDemo.Windows.ViewModels" + RequestedThemeVariant="Light" + x:Class="AvaloniaCoreRTDemo.App" + x:CompileBindings="True" + x:DataType="viewModels1:ApplicationModelBase"> + + + + + - - \ No newline at end of file diff --git a/src/App.axaml.cs b/src/App.axaml.cs index e0ead4d..8cf244d 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -1,11 +1,13 @@ - using System; + using Avalonia; +using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using Avalonia.Styling; using Avalonia.Themes.Fluent; using Avalonia.Themes.Simple; + using AvaloniaCoreRTDemo.Interfaces; using AvaloniaCoreRTDemo.Windows; @@ -13,10 +15,10 @@ namespace AvaloniaCoreRTDemo { public sealed class App : Application, IThemeSwitch { - private FluentTheme _fluentTheme; - private SimpleTheme _simpleTheme; - private IStyle _fluentDataGrid; - private IStyle _simpleDataGrid; + private FluentTheme _fluentTheme = default!; + private SimpleTheme _simpleTheme = default!; + private IStyle _fluentDataGrid = default!; + private IStyle _simpleDataGrid = default!; private ApplicationTheme _currentTheme; @@ -39,13 +41,14 @@ namespace AvaloniaCoreRTDemo private void InitializeThemes() { - this._fluentTheme = (FluentTheme)this.Resources["fluentTheme"]!; - this._simpleTheme = (SimpleTheme)this.Resources["simpleTheme"]!; + this._simpleTheme = new SimpleTheme(); + this._fluentTheme = new FluentTheme(); + this._fluentDataGrid = (IStyle)this.Resources["fluentDataGrid"]!; this._simpleDataGrid = (IStyle)this.Resources["simpleDataGrid"]!; + Styles.Add(_fluentTheme); Styles.Add(_fluentDataGrid); - this._currentTheme = ApplicationTheme.FluentLight; } @@ -53,48 +56,54 @@ namespace AvaloniaCoreRTDemo void IThemeSwitch.ChangeTheme(ApplicationTheme theme) { - var themeChanged = theme switch + if (theme == this._currentTheme) + return; + + Boolean themeChanged = theme switch { - ApplicationTheme.SimpleLight => _currentTheme is ApplicationTheme.FluentDark or ApplicationTheme.FluentLight, - ApplicationTheme.SimpleDark => _currentTheme is ApplicationTheme.FluentDark or ApplicationTheme.FluentLight, - ApplicationTheme.FluentLight => _currentTheme is ApplicationTheme.SimpleLight or ApplicationTheme.SimpleDark, - ApplicationTheme.FluentDark => _currentTheme is ApplicationTheme.SimpleLight or ApplicationTheme.SimpleDark, + ApplicationTheme.SimpleLight => this._currentTheme is ApplicationTheme.FluentDark or ApplicationTheme.FluentLight, + ApplicationTheme.SimpleDark => this._currentTheme is ApplicationTheme.FluentDark or ApplicationTheme.FluentLight, + ApplicationTheme.FluentLight => this._currentTheme is ApplicationTheme.SimpleLight or ApplicationTheme.SimpleDark, + ApplicationTheme.FluentDark => this._currentTheme is ApplicationTheme.SimpleLight or ApplicationTheme.SimpleDark, _ => throw new ArgumentOutOfRangeException(nameof(theme), theme, null) }; - + this._currentTheme = theme; switch (theme) { case ApplicationTheme.SimpleLight: - this._simpleTheme.Mode = SimpleThemeMode.Light; + this.SetValue(ThemeVariantScope.ActualThemeVariantProperty, ThemeVariant.Light); this.Styles[0] = this._simpleTheme; this.Styles[1] = this._simpleDataGrid; break; case ApplicationTheme.SimpleDark: - this._simpleTheme.Mode = SimpleThemeMode.Dark; + this.SetValue(ThemeVariantScope.ActualThemeVariantProperty, ThemeVariant.Dark); this.Styles[0] = this._simpleTheme; this.Styles[1] = this._simpleDataGrid; break; case ApplicationTheme.FluentLight: - this._fluentTheme.Mode = FluentThemeMode.Light; + this.SetValue(ThemeVariantScope.ActualThemeVariantProperty, ThemeVariant.Light); this.Styles[0] = this._fluentTheme; this.Styles[1] = this._fluentDataGrid; break; case ApplicationTheme.FluentDark: - this._fluentTheme.Mode = FluentThemeMode.Dark; + this.SetValue(ThemeVariantScope.ActualThemeVariantProperty, ThemeVariant.Dark); this.Styles[0] = this._fluentTheme; this.Styles[1] = this._fluentDataGrid; break; } - if (themeChanged && ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + if (themeChanged && this.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - var oldWindow = desktop.MainWindow; - var newWindow = new MainWindow(); + MainWindow oldWindow = (desktop.MainWindow as MainWindow)!; + MainWindow newWindow = new MainWindow(oldWindow); + desktop.MainWindow = newWindow; + this.DataContext = newWindow.DataContext; + + oldWindow.Hide(); newWindow.Show(); oldWindow.Close(); - this.DataContext = desktop.MainWindow.DataContext; } } } diff --git a/src/AvaloniaCoreRTDemo.csproj b/src/AvaloniaCoreRTDemo.csproj index 3651354..637fed2 100644 --- a/src/AvaloniaCoreRTDemo.csproj +++ b/src/AvaloniaCoreRTDemo.csproj @@ -2,25 +2,31 @@ - WinExe + WinExe + Exe net7.0 - x64 Assets/app.ico true + enable true - + true + true + + + true true true - + link + false - false + false true - true + true @@ -37,19 +43,20 @@ PreserveNewest PreserveNewest + - - - - - - + + + + + + - + - + diff --git a/src/Controls/MainControl.axaml b/src/Controls/MainControl.axaml index d443c2d..13c2ab2 100644 --- a/src/Controls/MainControl.axaml +++ b/src/Controls/MainControl.axaml @@ -2,11 +2,11 @@ xmlns:viewModels="clr-namespace:AvaloniaCoreRTDemo.Controls.ViewModels" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="AvaloniaCoreRTDemo.Controls.MainControl" x:CompileBindings="True" - x:DataType="viewModels:MainViewModel"> + x:DataType="viewModels:MainControlViewModel"> Welcome to Avalonia UI + NativeAOT! - + diff --git a/src/Controls/MainControl.axaml.cs b/src/Controls/MainControl.axaml.cs index 59d7185..52aa012 100644 --- a/src/Controls/MainControl.axaml.cs +++ b/src/Controls/MainControl.axaml.cs @@ -9,13 +9,18 @@ namespace AvaloniaCoreRTDemo.Controls { public MainControl() { - InitializeComponent(); + this.InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); - this.DataContext = new MainViewModel(); + this.DataContext = new MainControlViewModel(); + } + + public void Reload(IMainWindowState model) + { + this.DataContext = new MainControlViewModel(model); } } } diff --git a/src/Controls/ViewModels/MainControlViewModel.cs b/src/Controls/ViewModels/MainControlViewModel.cs new file mode 100644 index 0000000..8abe745 --- /dev/null +++ b/src/Controls/ViewModels/MainControlViewModel.cs @@ -0,0 +1,48 @@ +using System; + +using Avalonia.Media.Imaging; + +using ReactiveUI; + +namespace AvaloniaCoreRTDemo.Controls.ViewModels +{ + internal sealed class MainControlViewModel : ReactiveObject, IMainWindowState + { + private readonly IBitmap _dotNetImage; + private readonly IBitmap _avaloniaImage; + + private Boolean _unloadable = false; + + public IBitmap DotNetImage => this._dotNetImage; + public IBitmap AvaloniaImage => this._avaloniaImage; + public String? Text { get; set; } + + public MainControlViewModel() + { + this._dotNetImage = Utilities.GetImageFromFile("dotnet.png"); + this._avaloniaImage = Utilities.GetImageFromFile("avalonia.png"); + } + + public MainControlViewModel(IMainWindowState state) + { + this._avaloniaImage = state.AvaloniaImage; + this._dotNetImage = state.DotNetImage; + this.Text = state.Text; + state.SetUnloadable(); + } + + ~MainControlViewModel() + { + if (!this._unloadable) + { + this._dotNetImage.Dispose(); + this._avaloniaImage.Dispose(); + } + } + + void IMainWindowState.SetUnloadable() + { + this._unloadable = true; + } + } +} diff --git a/src/Controls/ViewModels/MainViewModel.cs b/src/Controls/ViewModels/MainViewModel.cs deleted file mode 100644 index f1cea96..0000000 --- a/src/Controls/ViewModels/MainViewModel.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.IO; - -using Avalonia.Media.Imaging; - -using ReactiveUI; - -namespace AvaloniaCoreRTDemo.Controls.ViewModels -{ - internal sealed class MainViewModel : ReactiveObject - { - private readonly IBitmap _dotNetImage; - private readonly IBitmap _avaloniaImage; - - public IBitmap DotNetImage => this._dotNetImage; - - public IBitmap AvaloniaImage => this._avaloniaImage; - - public MainViewModel() - { - this._dotNetImage = Utilities.GetImageFromFile("dotnet.png"); - this._avaloniaImage = Utilities.GetImageFromFile("avalonia.png"); - } - - ~MainViewModel() - { - this._dotNetImage.Dispose(); - this._avaloniaImage.Dispose(); - } - } -} diff --git a/src/Interfaces/IMainWindow.cs b/src/Interfaces/IMainWindow.cs index 2f8b2a8..065ef7d 100644 --- a/src/Interfaces/IMainWindow.cs +++ b/src/Interfaces/IMainWindow.cs @@ -1,9 +1,15 @@ -using AvaloniaCoreRTDemo.Interfaces; +using Avalonia; +using Avalonia.Controls; -namespace AvaloniaCoreRTDemo +namespace AvaloniaCoreRTDemo.Interfaces { public interface IMainWindow { IThemeSwitch ThemeSwitch { get; } + IMainWindowState Model { get; } + PixelPoint Position { get; } + Size ClientSize { get; } + Size? FrameSize { get; } + WindowState State { get; } } } diff --git a/src/Interfaces/IMainWindowState.cs b/src/Interfaces/IMainWindowState.cs new file mode 100644 index 0000000..ea25cce --- /dev/null +++ b/src/Interfaces/IMainWindowState.cs @@ -0,0 +1,16 @@ +using System; + +using Avalonia.Media.Imaging; + +namespace AvaloniaCoreRTDemo +{ + public interface IMainWindowState + { + IBitmap DotNetImage { get; } + IBitmap AvaloniaImage { get; } + String? Text { get; } + + void SetUnloadable(); + } +} + diff --git a/src/Utilities.cs b/src/Utilities.cs index 3b740ec..e51dcb7 100644 --- a/src/Utilities.cs +++ b/src/Utilities.cs @@ -1,7 +1,9 @@ using System; using System.IO; using System.Runtime.InteropServices; + using Avalonia; +using Avalonia.Controls; using Avalonia.Media.Imaging; using Avalonia.Platform; @@ -19,6 +21,17 @@ namespace AvaloniaCoreRTDemo return new Bitmap(assetStream); } + public static PixelPoint GetWindowPosition(Window window) + { + if (!IsOSX || !window.FrameSize.HasValue) + return window.Position; + else + { + Int32 yOffset = (Int32)(window.FrameSize.Value.Height - window.ClientSize.Height); + return new(window.Position.X, window.Position.Y + yOffset); + } + } + public static Bitmap GetImageFromFile(String path) { try @@ -30,7 +43,7 @@ namespace AvaloniaCoreRTDemo return GetImageFromResources("broken-link.png"); } } - + private static String GetImageFullPath(String fileName) => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName); } diff --git a/src/Windows/AboutWindow.axaml b/src/Windows/AboutWindow.axaml index 58e9b80..e1e5c51 100644 --- a/src/Windows/AboutWindow.axaml +++ b/src/Windows/AboutWindow.axaml @@ -10,7 +10,7 @@ - + diff --git a/src/Windows/AboutWindow.axaml.cs b/src/Windows/AboutWindow.axaml.cs index 4b9ca92..2676011 100644 --- a/src/Windows/AboutWindow.axaml.cs +++ b/src/Windows/AboutWindow.axaml.cs @@ -1,5 +1,6 @@ using System; +using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; @@ -9,20 +10,23 @@ namespace AvaloniaCoreRTDemo.Windows { public sealed partial class AboutWindow : Window { - public AboutWindow() - { - this.InitializeComponent(); - } + private readonly Boolean _darkTheme; + + public AboutWindow() : this(false) { } public AboutWindow(Boolean darkTheme) { - this.InitializeComponent(darkTheme); + this._darkTheme = darkTheme; + this.InitializeComponent(); +#if DEBUG + this.AttachDevTools(); +#endif } - private void InitializeComponent(Boolean darkTheme = default) + private void InitializeComponent() { AvaloniaXamlLoader.Load(this); - this.DataContext = new AboutViewModel(darkTheme); + this.DataContext = new AboutViewModel(this._darkTheme); } } } diff --git a/src/Windows/MainWindow.axaml b/src/Windows/MainWindow.axaml index e82bf20..3977e9b 100644 --- a/src/Windows/MainWindow.axaml +++ b/src/Windows/MainWindow.axaml @@ -4,10 +4,10 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="AvaloniaCoreRTDemo.Windows.MainWindow" Width="640" Height="480" WindowStartupLocation="CenterScreen" Title="AvaloniaCoreRTDemo" Icon="avares://AvaloniaCoreRTDemo/Assets/app.ico" MinWidth="400" MinHeight="350" x:CompileBindings="True" - x:DataType="viewModels1:MainViewModelBase"> + x:DataType="viewModels1:ApplicationModelBase"> - + diff --git a/src/Windows/MainWindow.axaml.cs b/src/Windows/MainWindow.axaml.cs index a846014..fd51056 100644 --- a/src/Windows/MainWindow.axaml.cs +++ b/src/Windows/MainWindow.axaml.cs @@ -1,28 +1,48 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; - -using AvaloniaCoreRTDemo.Interfaces; -using AvaloniaCoreRTDemo.Windows.ViewModels; - -namespace AvaloniaCoreRTDemo.Windows -{ - public sealed partial class MainWindow : Window, IMainWindow - { - public MainWindow() - { - InitializeComponent(); -#if DEBUG - this.AttachDevTools(); -#endif - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - this.DataContext = new MainViewModel(this); - } - - IThemeSwitch IMainWindow.ThemeSwitch => App.Current as IThemeSwitch; - } -} +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +using AvaloniaCoreRTDemo.Controls; +using AvaloniaCoreRTDemo.Interfaces; +using AvaloniaCoreRTDemo.Windows.ViewModels; + +namespace AvaloniaCoreRTDemo.Windows +{ + public sealed partial class MainWindow : Window, IMainWindow + { + private readonly Application? _app = App.Current; + + private MainControl MainControl => this.GetControl("MainControl"); + + public MainWindow() : this(default) { } + public MainWindow(IMainWindow? window) + { + this.InitializeComponent(window); +#if DEBUG + this.AttachDevTools(); +#endif + } + + IThemeSwitch IMainWindow.ThemeSwitch => (IThemeSwitch)this._app!; + IMainWindowState IMainWindow.Model => (IMainWindowState)this.MainControl.DataContext!; + PixelPoint IMainWindow.Position => Utilities.GetWindowPosition(this); + Size IMainWindow.ClientSize => this.ClientSize; + Size? IMainWindow.FrameSize => this.FrameSize; + WindowState IMainWindow.State => this.WindowState; + + private void InitializeComponent(IMainWindow? window) + { + AvaloniaXamlLoader.Load(this); + this.DataContext = new MainViewModel(this); + if (window is not null) + { + this.MainControl.Reload(window.Model); + this.WindowStartupLocation = WindowStartupLocation.Manual; + this.WindowState = window.State; + this.Position = window.Position; + this.FrameSize = window.FrameSize; + this.ClientSize = window.ClientSize; + } + } + } +} diff --git a/src/Windows/ViewModels/AboutViewModel.cs b/src/Windows/ViewModels/AboutViewModel.cs index 0cb018f..2e72d49 100644 --- a/src/Windows/ViewModels/AboutViewModel.cs +++ b/src/Windows/ViewModels/AboutViewModel.cs @@ -9,10 +9,10 @@ using ReactiveUI; namespace AvaloniaCoreRTDemo.Windows.ViewModels { internal record SystemDetail(string Key, string Value); - + internal sealed class AboutViewModel : ReactiveObject { - + private readonly IBitmap _computerImage; private readonly Boolean _darkTheme; diff --git a/src/Windows/ViewModels/MainViewModelBase.cs b/src/Windows/ViewModels/ApplicationModelBase.cs similarity index 68% rename from src/Windows/ViewModels/MainViewModelBase.cs rename to src/Windows/ViewModels/ApplicationModelBase.cs index f9d09da..62c4ee6 100644 --- a/src/Windows/ViewModels/MainViewModelBase.cs +++ b/src/Windows/ViewModels/ApplicationModelBase.cs @@ -1,5 +1,6 @@ using System; using System.Reactive; + using Avalonia.Controls; using AvaloniaCoreRTDemo.Interfaces; @@ -8,14 +9,14 @@ using ReactiveUI; namespace AvaloniaCoreRTDemo.Windows.ViewModels { - internal abstract class MainViewModelBase : ReactiveObject + internal abstract class ApplicationModelBase : ReactiveObject { private readonly IThemeSwitch _themeSwitch; private Boolean _aboutEnable = true; - private Boolean _defaultLightEnable = true; - private Boolean _defaultDarkEnable = true; - private Boolean _fluentLightEnable = true; - private Boolean _fluentDarkEnable = true; + private Boolean _defaultLightEnable = false; + private Boolean _defaultDarkEnable = false; + private Boolean _fluentLightEnable = false; + private Boolean _fluentDarkEnable = false; public Boolean AboutEnabled { @@ -23,12 +24,6 @@ namespace AvaloniaCoreRTDemo.Windows.ViewModels set => this.RaiseAndSetIfChanged(ref this._aboutEnable, value); } - public MainViewModelBase(IThemeSwitch window) - { - this._themeSwitch = window; - this.FileExitCommand = ReactiveCommand.Create(RunFileExit); - } - public Boolean DefaultLightEnabled { get => this._defaultLightEnable; @@ -52,19 +47,22 @@ namespace AvaloniaCoreRTDemo.Windows.ViewModels get => this._fluentDarkEnable; set => this.RaiseAndSetIfChanged(ref this._fluentDarkEnable, value); } - - public ReactiveCommand FileExitCommand { get; } - - public abstract void HelpAboutMethod(); + public ReactiveCommand FileExitCommand { get; } + + public ApplicationModelBase(IThemeSwitch themeSwitch) + { + this._themeSwitch = themeSwitch; + this.IntializeTheme(themeSwitch.Current); + this.FileExitCommand = ReactiveCommand.Create(RunFileExit); + } + + public abstract void HelpAboutMethod(); public abstract void DefaultLightMethod(); public abstract void DefaultDarkMethod(); public abstract void FluentLightMethod(); public abstract void FluentDarkMethod(); - - private void RunFileExit() - => Environment.Exit(0); - + protected async void RunHelpAbout(Window currentWindow) { if (this.AboutEnabled) @@ -79,6 +77,22 @@ namespace AvaloniaCoreRTDemo.Windows.ViewModels } } + protected void SetTheme(ApplicationTheme theme) + { + this.IntializeTheme(theme); + this._themeSwitch.ChangeTheme(theme); + } + + private void RunFileExit() => Environment.Exit(0); + + private void IntializeTheme(ApplicationTheme theme) + { + this.DefaultLightEnabled = theme != ApplicationTheme.SimpleLight; + this.DefaultDarkEnabled = theme != ApplicationTheme.SimpleDark; + this.FluentLightEnabled = theme != ApplicationTheme.FluentLight; + this.FluentDarkEnabled = theme != ApplicationTheme.FluentDark; + } + private static Boolean IsDarkTheme(ApplicationTheme? theme) => theme switch { diff --git a/src/Windows/ViewModels/MainViewModel.cs b/src/Windows/ViewModels/MainViewModel.cs index 3bd40b8..b464ee2 100644 --- a/src/Windows/ViewModels/MainViewModel.cs +++ b/src/Windows/ViewModels/MainViewModel.cs @@ -1,39 +1,24 @@ -using System; -using System.Reactive; +using Avalonia.Controls; -using Avalonia.Controls; - -using ReactiveUI; +using AvaloniaCoreRTDemo.Interfaces; namespace AvaloniaCoreRTDemo.Windows.ViewModels { - internal sealed class MainViewModel : MainViewModelBase + internal sealed class MainViewModel : ApplicationModelBase where TWindow : Window, IMainWindow { - private readonly TWindow _window; + private TWindow _window; public MainViewModel(TWindow window) : base(window.ThemeSwitch) { this._window = window; - this.ChangeTheme(window.ThemeSwitch.Current); } - public override void HelpAboutMethod() => base.RunHelpAbout(this._window); - - public override void DefaultLightMethod() => this.ChangeTheme(ApplicationTheme.SimpleLight); - public override void DefaultDarkMethod() => this.ChangeTheme(ApplicationTheme.SimpleDark); - public override void FluentLightMethod() => this.ChangeTheme(ApplicationTheme.FluentLight); - public override void FluentDarkMethod() => this.ChangeTheme(ApplicationTheme.FluentDark); - - private void ChangeTheme(ApplicationTheme theme) - { - this.DefaultLightEnabled = theme != ApplicationTheme.SimpleLight; - this.DefaultDarkEnabled = theme != ApplicationTheme.SimpleDark; - this.FluentLightEnabled = theme != ApplicationTheme.FluentLight; - this.FluentDarkEnabled = theme != ApplicationTheme.FluentDark; - this._window.ThemeSwitch?.ChangeTheme(theme); - } + public override void DefaultLightMethod() => base.SetTheme(ApplicationTheme.SimpleLight); + public override void DefaultDarkMethod() => base.SetTheme(ApplicationTheme.SimpleDark); + public override void FluentLightMethod() => base.SetTheme(ApplicationTheme.FluentLight); + public override void FluentDarkMethod() => base.SetTheme(ApplicationTheme.FluentDark); } } diff --git a/src/nuget.config b/src/nuget.config index 3d11832..72fcfd7 100644 --- a/src/nuget.config +++ b/src/nuget.config @@ -1,7 +1,7 @@ - + diff --git a/test.cmd b/test.cmd index c9bf3b9..90ebc8d 100644 --- a/test.cmd +++ b/test.cmd @@ -1,2 +1,2 @@ del src\packages.lock.json -dotnet publish -r win-x64 -c release /p:RestoreLockedMode=true /p:TrimLink=true --self-contained \ No newline at end of file +dotnet publish -r win-x64 -c Release /p:RestoreLockedMode=true \ No newline at end of file diff --git a/test.command b/test.command index 674b2ba..46a3a1d 100755 --- a/test.command +++ b/test.command @@ -4,7 +4,7 @@ if [ -d "$dir" ]; then cd "$dir" fi rm -f src/packages.lock.json -dotnet publish -r osx-x64 -c release /p:RestoreLockedMode=true -t:BundleApp /p:TrimLink=true --self-contained -rm -rf src/bin/x64/Release/net7.0/osx-x64/publish/Assets/ -rm -rf src/bin/x64/Release/net7.0/osx-x64/publish/AvaloniaCoreRTDemo.app/Contents/MacOS/Assets/ -rm src/bin/x64/Release/net7.0/osx-x64/publish/AvaloniaCoreRTDemo.app/Contents/MacOS/AvaloniaCoreRTDemo.dwarf \ No newline at end of file +dotnet publish -r osx-x64 -c Release /p:RestoreLockedMode=true -t:BundleApp +rm -rf src/bin/Release/net7.0/osx-x64/publish/Assets/ +rm -rf src/bin/Release/net7.0/osx-x64/publish/AvaloniaCoreRTDemo.app/Contents/MacOS/Assets/ +rm src/bin/Release/net7.0/osx-x64/publish/AvaloniaCoreRTDemo.app/Contents/MacOS/AvaloniaCoreRTDemo.dwarf \ No newline at end of file diff --git a/test.sh b/test.sh index cefc25d..6a03349 100644 --- a/test.sh +++ b/test.sh @@ -1,6 +1,5 @@ #!/bin/bash rm -f src/packages.lock.json -dotnet publish -r linux-x64 -c release /p:RestoreLockedMode=true /p:TrimLink=true --self-contained -cd src/bin/x64/Release/net7.0/linux-x64/publish +dotnet publish -r linux-x64 -c Release /p:RestoreLockedMode=true +cd src/bin/Release/net7.0/linux-x64/publish cp AvaloniaCoreRTDemo AvaloniaCoreRTDemo.bin -strip AvaloniaCoreRTDemo.bin