Compare commits

..

No commits in common. "main" and "v0.10" have entirely different histories.
main ... v0.10

34 changed files with 692 additions and 763 deletions

View File

@ -16,7 +16,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 7.0.x
dotnet-version: 6.0.x
- name: Publish
run: |
sudo chmod +x ./test.sh
@ -25,9 +25,9 @@ jobs:
with:
name: Linux-Artifact
path: |
./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
./src/bin/x64/Release/net6.0/linux-x64/publish/*.bin
./src/bin/x64/Release/net6.0/linux-x64/publish/*.so
./src/bin/x64/Release/net6.0/linux-x64/publish/*.png
build-on-windows:
runs-on: windows-latest
steps:
@ -35,16 +35,16 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 7.0.x
dotnet-version: 6.0.x
- name: Publish
run: ./test.cmd
- uses: actions/upload-artifact@v2
with:
name: Windows-Artifact
path: |
.\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
.\src\bin\x64\Release\net6.0\win-x64\publish\*.exe
.\src\bin\x64\Release\net6.0\win-x64\publish\*.dll
.\src\bin\x64\Release\net6.0\win-x64\publish\*.png
build-on-macos:
runs-on: macos-latest
steps:
@ -52,14 +52,14 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 7.0.x
dotnet-version: 6.0.x
- name: Publish
run: |
sudo chmod +x ./test.command
./test.command
cd ./src/bin/Release/net7.0/osx-x64/publish
cd ./src/bin/x64/Release/net6.0/osx-x64/publish
zip -r -0 macOS-Artifact.zip *.app
mv *.zip ../../../../../../.
mv *.zip ../../../../../../../.
- uses: actions/upload-artifact@v2
with:
name: macOS-Artifact

View File

@ -7,14 +7,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaCoreRTDemo", "src\A
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{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
{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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -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 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.
* .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.
* Git. Install [Git for Windows](https://git-scm.com/download/win).
## Getting started
@ -34,6 +34,8 @@ 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

View File

@ -1,26 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/bin/Debug/net7.0/linux-x64/AvaloniaCoreRTDemo.dll",
"args": [],
"cwd": "${workspaceFolder}",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}

View File

@ -1,41 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/AvaloniaCoreRTDemo.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/AvaloniaCoreRTDemo.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/AvaloniaCoreRTDemo.csproj"
],
"problemMatcher": "$msCompile"
}
]
}

View File

@ -1,22 +1,18 @@
<Application
x:Class="AvaloniaCoreRTDemo.App"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels1="clr-namespace:AvaloniaCoreRTDemo.Windows.ViewModels"
x:CompileBindings="True"
x:DataType="viewModels1:ApplicationModelBase"
RequestedThemeVariant="Light">
<NativeMenu.Menu>
<NativeMenu>
<NativeMenuItem
Command="{Binding HelpAboutCommand}"
Gesture="cmd+b"
Header="About"
IsEnabled="{Binding AboutEnabled}" />
</NativeMenu>
</NativeMenu.Menu>
<Application.Resources>
<StyleInclude x:Key="fluentDataGrid" Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml" />
<StyleInclude x:Key="simpleDataGrid" Source="avares://Avalonia.Controls.DataGrid/Themes/Simple.xaml" />
</Application.Resources>
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="AvaloniaCoreRTDemo.App">
<NativeMenu.Menu>
<NativeMenu>
<NativeMenuItem Header="About" Gesture="cmd+b" IsEnabled="{Binding AboutEnabled}" Command="{Binding HelpAboutMethod}"/>
</NativeMenu>
</NativeMenu.Menu>
<Application.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseDark.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/>
</Application.Styles>
<Application.Resources>
<FluentTheme x:Key="fluentLight" Mode="Light" />
<FluentTheme x:Key="fluentDark" Mode="Dark" />
</Application.Resources>
</Application>

View File

@ -1,108 +1,83 @@
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;
namespace AvaloniaCoreRTDemo;
public sealed class App : Application, IThemeSwitch
namespace AvaloniaCoreRTDemo
{
private FluentTheme _fluentTheme = default!;
private SimpleTheme _simpleTheme = default!;
private IStyle _fluentDataGrid = default!;
private IStyle _simpleDataGrid = default!;
private ApplicationTheme _currentTheme;
public override void Initialize()
public sealed class App : Application, IThemeSwitch
{
AvaloniaXamlLoader.Load(this);
Name = "AvaloniaCoreRTDemo";
}
private IStyle _baseLight;
private IStyle _baseDark;
public override void OnFrameworkInitializationCompleted()
{
InitializeThemes();
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
private IStyle _fluentLight;
private IStyle _fluentDark;
private ApplicationTheme _currentTheme;
public override void Initialize()
{
desktop.MainWindow = new MainWindow();
DataContext = desktop.MainWindow.DataContext;
}
base.OnFrameworkInitializationCompleted();
}
private void InitializeThemes()
{
_simpleTheme = new SimpleTheme();
_fluentTheme = new FluentTheme();
_fluentDataGrid = (IStyle)Resources["fluentDataGrid"]!;
_simpleDataGrid = (IStyle)Resources["simpleDataGrid"]!;
Styles.Add(_fluentTheme);
Styles.Add(_fluentDataGrid);
_currentTheme = ApplicationTheme.FluentLight;
}
ApplicationTheme IThemeSwitch.Current => _currentTheme;
void IThemeSwitch.ChangeTheme(ApplicationTheme theme)
{
if (theme == _currentTheme)
return;
var 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,
_ => throw new ArgumentOutOfRangeException(nameof(theme), theme, null)
};
_currentTheme = theme;
switch (theme)
{
case ApplicationTheme.SimpleLight:
SetValue(ThemeVariantScope.ActualThemeVariantProperty, ThemeVariant.Light);
Styles[0] = _simpleTheme;
Styles[1] = _simpleDataGrid;
break;
case ApplicationTheme.SimpleDark:
SetValue(ThemeVariantScope.ActualThemeVariantProperty, ThemeVariant.Dark);
Styles[0] = _simpleTheme;
Styles[1] = _simpleDataGrid;
break;
case ApplicationTheme.FluentLight:
SetValue(ThemeVariantScope.ActualThemeVariantProperty, ThemeVariant.Light);
Styles[0] = _fluentTheme;
Styles[1] = _fluentDataGrid;
break;
case ApplicationTheme.FluentDark:
SetValue(ThemeVariantScope.ActualThemeVariantProperty, ThemeVariant.Dark);
Styles[0] = _fluentTheme;
Styles[1] = _fluentDataGrid;
break;
AvaloniaXamlLoader.Load(this);
this.Name = "AvaloniaCoreRTDemo";
}
if (!themeChanged || ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) return;
var oldWindow = (desktop.MainWindow as MainWindow)!;
var newWindow = new MainWindow(oldWindow);
public override void OnFrameworkInitializationCompleted()
{
this.InitializeThemes();
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = !Utilities.IsOSX ? new MainWindow() : new MainWindowMacOS();
this.DataContext = desktop.MainWindow.DataContext;
}
base.OnFrameworkInitializationCompleted();
}
desktop.MainWindow = newWindow;
DataContext = newWindow.DataContext;
private void InitializeThemes()
{
this._baseDark = this.Styles[0];
this._baseLight = this.Styles[1];
oldWindow.Hide();
newWindow.Show();
oldWindow.Close();
this.Styles.Remove(this._baseDark);
this._fluentLight = (FluentTheme)this.Resources["fluentLight"]!;
this._fluentDark = (FluentTheme)this.Resources["fluentDark"]!;
this._currentTheme = ApplicationTheme.DefaultLight;
}
ApplicationTheme IThemeSwitch.Current => this._currentTheme;
void IThemeSwitch.ChangeTheme(ApplicationTheme theme)
{
this._currentTheme = theme;
switch (theme)
{
case ApplicationTheme.DefaultLight:
this.Styles[0] = this._baseLight;
this.Styles.Remove(this._baseDark);
break;
case ApplicationTheme.DefaultDark:
this.Styles[0] = this._baseDark;
this.Styles.Remove(this._baseLight);
break;
case ApplicationTheme.FluentLight:
this.Styles[0] = this._fluentLight;
this.Styles.Remove(this._fluentDark);
if (!this.Styles.Contains(this._baseLight))
this.Styles.Add(this._baseLight);
break;
case ApplicationTheme.FluentDark:
this.Styles[0] = this._fluentDark;
this.Styles.Remove(this._baseLight);
if (!this.Styles.Contains(this._baseDark))
this.Styles.Add(this._baseDark);
break;
}
}
}
}

View File

@ -1,9 +1,12 @@
namespace AvaloniaCoreRTDemo;
using System;
public enum ApplicationTheme : byte
namespace AvaloniaCoreRTDemo
{
SimpleLight = 0,
SimpleDark = 1,
FluentLight = 2,
FluentDark = 3,
public enum ApplicationTheme : Byte
{
DefaultLight = 0,
DefaultDark = 1,
FluentLight = 2,
FluentDark = 3,
}
}

View File

@ -2,69 +2,59 @@
<PropertyGroup>
<!-- if you want to check exceptions, change this to "Exe" and start your app from the console -->
<OutputType Condition="'$(Configuration.toUpper())' != 'DEBUG'">WinExe</OutputType>
<OutputType Condition="'$(Configuration.toUpper())' == 'DEBUG'">Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Platforms>x64</Platforms>
<ApplicationIcon>Assets/app.ico</ApplicationIcon>
<InvariantGlobalization>true</InvariantGlobalization>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<PublishTrimmed>true</PublishTrimmed>
<SelfContained>true</SelfContained>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<PropertyGroup>
<!--https://docs.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options-->
<TrimmerDefaultAction>link</TrimmerDefaultAction>
<IsWindows Condition="$([MSBuild]::IsOSPlatform('Windows'))">true</IsWindows>
<IsLinux Condition="$([MSBuild]::IsOSPlatform('Linux'))">true</IsLinux>
<IsOSX Condition="$([MSBuild]::IsOSPlatform('OSX'))">true</IsOSX>
<DefineConstants Condition="'$(IsOSX)'=='true'">OSX</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<TrimMode>link</TrimMode>
<!--These can help when debugging weird exceptions especially when reflection is involved. See https://github.com/dotnet/corert/blob/master/Documentation/using-corert/optimizing-corert.md -->
<!--Tthese can help when debugging weird exceptions especially when reflection is involved. See https://github.com/dotnet/corert/blob/master/Documentation/using-corert/optimizing-corert.md -->
<!--RootAllApplicationAssemblies: False -> TrimMode:link See https://github.com/dotnet/runtimelab/issues/597 and https://github.com/dotnet/runtimelab/blob/feature/NativeAOT/docs/using-nativeaot/optimizing.md -->
<IlcGenerateCompleteTypeMetadata>false</IlcGenerateCompleteTypeMetadata>
<IlcGenerateStackTraceData Condition="'$(Configuration.toUpper())' != 'DEBUG'">false</IlcGenerateStackTraceData>
<IlcGenerateStackTraceData>false</IlcGenerateStackTraceData>
<IlcDisableUnhandledExceptionExperience>true</IlcDisableUnhandledExceptionExperience>
<StripSymbols Condition="'$(Configuration.toUpper())' != 'DEBUG'">true</StripSymbols>
</PropertyGroup>
<!-- Instruct NativeAOT to use this native dependency, required to build Avalonia. This library comes from the Windows SDK. -->
<ItemGroup Condition="'$(IsWindows)'=='true'">
<NativeLibrary Include="WindowsApp.lib" />
</ItemGroup>
<ItemGroup>
<AvaloniaResource Include="Assets/**" />
<AvaloniaResource Include="Images/**" />
<EmbeddedResource Include="Images/**" />
<None Update="avalonia.png" CopyToPublishDirectory="PreserveNewest">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="dotnet.png" CopyToPublishDirectory="PreserveNewest">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets/app.icns" CopyToPublishDirectory="PreserveNewest" Condition="$(RuntimeIdentifier.StartsWith('osx'))">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="dotnet.png">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="avalonia.png">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<RuntimeHostConfigurationOption Include="Switch.System.Reflection.Assembly.SimulatedCallingAssembly" Value="true" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.1.3" />
<PackageReference Include="Avalonia.Desktop" Version="11.1.3" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.1.3" />
<PackageReference Include="Avalonia.Themes.Simple" Version="11.1.3" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.1.3" />
<PackageReference Include="Avalonia" Version="0.10.18" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.18" />
<PackageReference Include="Avalonia.Native" Version="0.10.18" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.18" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.3" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.18" />
<!--Condition below is needed to generate macOS App only.-->
<PackageReference Include="Dotnet.Bundle" Version="0.9.13" Condition="$(RuntimeIdentifier.StartsWith('osx'))" />
<PackageReference Include="MvvmGen.PureCodeGeneration" Version="1.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Dotnet.Bundle" Version="*" Condition="$(RuntimeIdentifier.StartsWith('osx'))" />
</ItemGroup>
<!-- Information for Dotnet.Bundle to Generate macOS app-->
<PropertyGroup>
<PropertyGroup Condition="'$(IsOSX)'=='true'">
<CFBundleName>$(AssemblyName)</CFBundleName>
<CFBundleDisplayName>$(AssemblyName)</CFBundleDisplayName>
<CFBundleIdentifier>com.$(username).$(AssemblyName)</CFBundleIdentifier>
@ -80,4 +70,39 @@
<NSRequiresAquaSystemAppearance>true</NSRequiresAquaSystemAppearance>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.DotNet.ILCompiler" Version="8.0.0-*" />
<!-- Avalonia relies heavily on reflection. Describe types reflected upon here. -->
<RdXmlFile Include="rd.xml" />
<RuntimeHostConfigurationOption Include="Switch.System.Reflection.Assembly.SimulatedCallingAssembly" Value="true" />
</ItemGroup>
<!--App axaml-->
<ItemGroup>
<Compile Update="App.axaml.cs">
<DependentUpon>App.axaml</DependentUpon>
</Compile>
</ItemGroup>
<!--Cross platform xaml-->
<ItemGroup>
<Compile Update="Controls/MainControl.axaml.cs">
<DependentUpon>MainControl.axaml</DependentUpon>
</Compile>
<Compile Update="Windows/AboutWindow.axaml.cs">
<DependentUpon>AboutWindow.axaml</DependentUpon>
</Compile>
</ItemGroup>
<!--No-OSX only xaml-->
<ItemGroup Condition="'$(IsOSX)'!='true'">
<Compile Update="Windows/MainWindow.axaml.cs">
<DependentUpon>MainWindow.axaml</DependentUpon>
</Compile>
</ItemGroup>
<!--OSX only xaml-->
<ItemGroup Condition="'$(IsOSX)'=='true'">
<Compile Update="Windows/MainWindowMacOS.axaml.cs">
<DependentUpon>MainWindowMacOS.axaml</DependentUpon>
</Compile>
</ItemGroup>
</Project>

View File

@ -1,44 +1,9 @@
<UserControl
x:Class="AvaloniaCoreRTDemo.Controls.MainControl"
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:viewModels="clr-namespace:AvaloniaCoreRTDemo.Controls.ViewModels"
d:DesignHeight="450"
d:DesignWidth="800"
x:CompileBindings="True"
x:DataType="viewModels:MainControlViewModel"
mc:Ignorable="d">
<Grid
Margin="32"
ColumnDefinitions="*,*"
RowDefinitions="Auto,Auto,*">
<TextBlock
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="0,6"
TextAlignment="Center">
Welcome to Avalonia UI + NativeAOT!
</TextBlock>
<Image
Grid.Row="1"
Grid.Column="0"
Source="{Binding DotNetImage}"
Stretch="None" />
<Image
Grid.Row="1"
Grid.Column="1"
Source="{Binding AvaloniaImage}"
Stretch="None" />
<TextBox
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="2"
AcceptsReturn="True"
Text="{Binding Text}"
TextWrapping="Wrap"
Watermark="Type here" />
</Grid>
<UserControl 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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="AvaloniaCoreRTDemo.Controls.MainControl">
<Grid ColumnDefinitions="*,*" RowDefinitions="Auto,Auto,*" Margin="32">
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" TextAlignment="Center" Margin="0,6">Welcome to Avalonia UI + NativeAOT!</TextBlock>
<Image Grid.Row="1" Grid.Column="0" Stretch="None" Source="{Binding DotNetImage}"/>
<Image Grid.Row="1" Grid.Column="1" Stretch="None" Source="{Binding AvaloniaImage}"/>
<TextBox Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Watermark="Type here" AcceptsReturn="True" TextWrapping="Wrap"/>
</Grid>
</UserControl>

View File

@ -1,24 +1,21 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using AvaloniaCoreRTDemo.Controls.ViewModels;
namespace AvaloniaCoreRTDemo.Controls;
public sealed partial class MainControl : UserControl
namespace AvaloniaCoreRTDemo.Controls
{
public MainControl()
public sealed partial class MainControl : UserControl
{
InitializeComponent();
}
public MainControl()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
DataContext = new MainControlViewModel();
}
public void Reload(IMainWindowState model)
{
DataContext = new MainControlViewModel(model);
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
this.DataContext = new MainViewModel();
}
}
}

View File

@ -1,45 +0,0 @@
using Avalonia.Media.Imaging;
namespace AvaloniaCoreRTDemo.Controls.ViewModels;
[ViewModel]
internal sealed partial class MainControlViewModel : IMainWindowState
{
private Bitmap _dotNetImage;
private Bitmap _avaloniaImage;
private bool _unloadable = false;
public Bitmap DotNetImage => _dotNetImage;
public Bitmap AvaloniaImage => _avaloniaImage;
public string? Text { get; set; }
partial void OnInitialize()
{
_dotNetImage = Utilities.GetImageFromFile("dotnet.png");
_avaloniaImage = Utilities.GetImageFromFile("avalonia.png");
}
public MainControlViewModel(IMainWindowState state)
: this()
{
_avaloniaImage = state.AvaloniaImage;
_dotNetImage = state.DotNetImage;
Text = state.Text;
state.SetUnloadable();
}
~MainControlViewModel()
{
if (!_unloadable)
{
_dotNetImage.Dispose();
_avaloniaImage.Dispose();
}
}
void IMainWindowState.SetUnloadable()
{
_unloadable = true;
}
}

View File

@ -0,0 +1,34 @@
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(GetImageFullPath("dotnet.png"));
this._avaloniaImage = Utilities.GetImageFromFile(GetImageFullPath("avalonia.png"));
}
private static String GetImageFullPath(String fileName)
=> Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
~MainViewModel()
{
this._dotNetImage.Dispose();
this._avaloniaImage.Dispose();
}
}
}

View File

@ -1,3 +0,0 @@
// Global using directives
global using MvvmGen;

View File

@ -1,14 +1,9 @@
using Avalonia;
using Avalonia.Controls;
using AvaloniaCoreRTDemo.Interfaces;
namespace AvaloniaCoreRTDemo.Interfaces;
public interface IMainWindow
namespace AvaloniaCoreRTDemo
{
IThemeSwitch ThemeSwitch { get; }
IMainWindowState Model { get; }
PixelPoint Position { get; }
Size ClientSize { get; }
Size? FrameSize { get; }
WindowState State { get; }
public interface IMainWindow
{
IThemeSwitch ThemeSwitch { get; }
}
}

View File

@ -1,12 +0,0 @@
using Avalonia.Media.Imaging;
namespace AvaloniaCoreRTDemo;
public interface IMainWindowState
{
Bitmap DotNetImage { get; }
Bitmap AvaloniaImage { get; }
string? Text { get; }
void SetUnloadable();
}

View File

@ -1,7 +1,8 @@
namespace AvaloniaCoreRTDemo.Interfaces;
public interface IThemeSwitch
namespace AvaloniaCoreRTDemo.Interfaces
{
ApplicationTheme Current { get; }
void ChangeTheme(ApplicationTheme theme);
public interface IThemeSwitch
{
ApplicationTheme Current { get; }
void ChangeTheme(ApplicationTheme theme);
}
}

View File

@ -1,16 +1,21 @@
using Avalonia;
namespace AvaloniaCoreRTDemo;
public static class Program
namespace AvaloniaCoreRTDemo
{
// 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.
public static void Main(string[] args) =>
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
public static 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.
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<App>().UsePlatformDetect().LogToTrace();
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>().UsePlatformDetect()
.UseAvaloniaNativeOSX()
.LogToTrace();
private static AppBuilder UseAvaloniaNativeOSX(this AppBuilder appBuilder)
=> Utilities.IsOSX ? appBuilder.UseAvaloniaNative() : appBuilder;
}
}

View File

@ -1,44 +1,39 @@
using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Controls;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
namespace AvaloniaCoreRTDemo;
internal static class Utilities
namespace AvaloniaCoreRTDemo
{
public static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
public static readonly bool IsOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
public static Bitmap GetImageFromResources(string fileName)
internal static class Utilities
{
using var assetStream = AssetLoader.Open(
new Uri($"avares://AvaloniaCoreRTDemo/Images/{fileName}")
);
return new Bitmap(assetStream);
}
public static readonly Boolean IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
public static readonly Boolean IsOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
public static PixelPoint GetWindowPosition(Window window)
{
if (!IsOSX || !window.FrameSize.HasValue)
return window.Position;
var yOffset = (int)(window.FrameSize.Value.Height - window.ClientSize.Height);
return new(window.Position.X, window.Position.Y + yOffset);
}
public static Bitmap GetImageFromFile(string path)
{
try
public static Bitmap GetImageFromResources(String fileName)
{
return new Bitmap(GetImageFullPath(path));
Assembly asm = Assembly.GetExecutingAssembly();
String resourceName = asm.GetManifestResourceNames().FirstOrDefault(str => str.EndsWith(fileName));
if (resourceName != null)
using (Stream bitmapStream = asm.GetManifestResourceStream(resourceName))
return new Bitmap(bitmapStream);
else
return default;
}
catch (Exception)
public static Bitmap GetImageFromFile(String path)
{
return GetImageFromResources("broken-link.png");
try
{
return new Bitmap(path);
}
catch (Exception)
{
return GetImageFromResources("broken-link.png");
}
}
}
private static string GetImageFullPath(string fileName) =>
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
}

View File

@ -1,50 +1,64 @@
<Window
x:Class="AvaloniaCoreRTDemo.Windows.AboutWindow"
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:viewModels="clr-namespace:AvaloniaCoreRTDemo.Windows.ViewModels"
Title="About"
Height="256"
MaxWidth="840"
d:DesignHeight="256"
d:DesignWidth="640"
x:CompileBindings="True"
x:DataType="viewModels:AboutViewModel"
CanResize="false"
Icon="avares://AvaloniaCoreRTDemo/Assets/about.ico"
ShowInTaskbar="False"
SizeToContent="Width"
WindowStartupLocation="CenterOwner"
WindowState="Normal"
mc:Ignorable="d">
<Grid
HorizontalAlignment="Left"
VerticalAlignment="Top"
ColumnDefinitions="Auto,*">
<Image
Grid.Column="0"
Margin="0,60"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Source="{Binding ComputerImage}"
Stretch="None" />
<DataGrid
Grid.Column="1"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
CanUserSortColumns="False"
HeadersVisibility="None"
IsReadOnly="True"
ItemsSource="{Binding SystemDetails}">
<DataGrid.Columns>
<DataGridTextColumn
Binding="{Binding Key, x:DataType=viewModels:SystemDetail}"
FontWeight="Bold"
Header="Key" />
<DataGridTextColumn Binding="{Binding Value, x:DataType=viewModels:SystemDetail}" Header="Value" />
</DataGrid.Columns>
</DataGrid>
</Grid>
<Window 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"
mc:Ignorable="d" x:Class="AvaloniaCoreRTDemo.Windows.AboutWindow" d:DesignWidth="640" d:DesignHeight="256"
WindowState="Normal" WindowStartupLocation="CenterOwner" MinHeight="256" MinWidth="640" Height="256" Width="640" MaxHeight="256" MaxWidth="640" Title="About" CanResize="false" ShowInTaskbar="False" Icon="avares://AvaloniaCoreRTDemo/Assets/about.ico">
<Grid VerticalAlignment="Top" HorizontalAlignment="Left" ColumnDefinitions="Auto,Auto" RowDefinitions="Auto">
<Image Margin="0, 60" Grid.Row="0" Grid.Column="0" Stretch="None" Source="{Binding ComputerImage}" VerticalAlignment="Top" HorizontalAlignment="Left">
</Image>
<ScrollViewer Margin="0, 10" Width="500" Height="230" Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Left" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto">
<Grid ColumnDefinitions="Auto" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<Grid Grid.Row="0" Grid.Column="0" ColumnDefinitions="Auto,Auto" RowDefinitions="Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" FontWeight="Bold" Text="Number of Cores: "/>
<TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" Text="{Binding NCores}"/>
</Grid>
<Grid Grid.Row="1" Grid.Column="0" ColumnDefinitions="Auto,Auto" RowDefinitions="Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" FontWeight="Bold" Text="OS: "/>
<TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" Text="{Binding OS}"/>
</Grid>
<Grid Grid.Row="2" Grid.Column="0" ColumnDefinitions="Auto,Auto" RowDefinitions="Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" FontWeight="Bold" Text="OS Arch: "/>
<TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" Text="{Binding OSArch}"/>
</Grid>
<Grid Grid.Row="3" Grid.Column="0" ColumnDefinitions="Auto,Auto" RowDefinitions="Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" FontWeight="Bold" Text="OS Version: "/>
<TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" Text="{Binding OSVersion}"/>
</Grid>
<Grid Grid.Row="4" Grid.Column="0" ColumnDefinitions="Auto,Auto" RowDefinitions="Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" FontWeight="Bold" Text="Computer: "/>
<TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" Text="{Binding ComputerName}"/>
</Grid>
<Grid Grid.Row="5" Grid.Column="0" ColumnDefinitions="Auto,Auto" RowDefinitions="Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" FontWeight="Bold" Text="User: "/>
<TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" Text="{Binding UserName}"/>
</Grid>
<Grid Grid.Row="6" Grid.Column="0" ColumnDefinitions="Auto,Auto" RowDefinitions="Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" FontWeight="Bold" Text="System Path: "/>
<TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" Text="{Binding SystemPath}"/>
</Grid>
<Grid Grid.Row="7" Grid.Column="0" ColumnDefinitions="Auto,Auto" RowDefinitions="Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" FontWeight="Bold" Text="Current Path: "/>
<TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" Text="{Binding CurrentPath}"/>
</Grid>
<Grid Grid.Row="8" Grid.Column="0" ColumnDefinitions="Auto,Auto" RowDefinitions="Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" FontWeight="Bold" Text="Process Arch: "/>
<TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" Text="{Binding ProcessArch}"/>
</Grid>
<Grid Grid.Row="9" Grid.Column="0" ColumnDefinitions="Auto,Auto" RowDefinitions="Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" FontWeight="Bold" Text="Runtime Name: "/>
<TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" Text="{Binding RuntimeName}"/>
</Grid>
<Grid Grid.Row="10" Grid.Column="0" ColumnDefinitions="Auto,Auto" RowDefinitions="Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" FontWeight="Bold" Text="Runtime Path: "/>
<TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" Text="{Binding RuntimePath}"/>
</Grid>
<Grid Grid.Row="11" Grid.Column="0" ColumnDefinitions="Auto,Auto" RowDefinitions="Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" FontWeight="Bold" Text="Runtime Version: "/>
<TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" Text="{Binding RuntimeVersion}"/>
</Grid>
<Grid Grid.Row="12" Grid.Column="0" ColumnDefinitions="Auto,Auto" RowDefinitions="Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" FontWeight="Bold" Text="Framework Version: "/>
<TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Left" Text="{Binding FrameworkVersion}"/>
</Grid>
</Grid>
</ScrollViewer>
</Grid>
</Window>

View File

@ -1,28 +1,28 @@
using System;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using AvaloniaCoreRTDemo.Windows.ViewModels;
namespace AvaloniaCoreRTDemo.Windows;
public sealed partial class AboutWindow : Window
namespace AvaloniaCoreRTDemo.Windows
{
private readonly bool _darkTheme;
public AboutWindow()
: this(false) { }
public AboutWindow(bool darkTheme)
public sealed partial class AboutWindow : Window
{
_darkTheme = darkTheme;
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
public AboutWindow()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
DataContext = new AboutViewModel(_darkTheme);
public AboutWindow(Boolean darkTheme)
{
this.InitializeComponent(darkTheme);
}
private void InitializeComponent(Boolean darkTheme = default)
{
AvaloniaXamlLoader.Load(this);
this.DataContext = new AboutViewModel(darkTheme);
}
}
}

View File

@ -1,66 +1,21 @@
<Window
x:Class="AvaloniaCoreRTDemo.Windows.MainWindow"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:AvaloniaCoreRTDemo.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels1="clr-namespace:AvaloniaCoreRTDemo.Windows.ViewModels"
Title="AvaloniaCoreRTDemo"
Width="640"
Height="480"
MinWidth="400"
MinHeight="350"
d:DesignHeight="450"
d:DesignWidth="800"
x:CompileBindings="True"
x:DataType="viewModels1:ApplicationModelBase"
Icon="avares://AvaloniaCoreRTDemo/Assets/app.ico"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<DockPanel>
<NativeMenuBar DockPanel.Dock="Top" />
<controls:MainControl Name="MainControl" />
</DockPanel>
<NativeMenu.Menu>
<NativeMenu>
<NativeMenuItem Header="File">
<NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem
Command="{Binding FileExitCommand}"
Gesture="cmd+e"
Header="Exit" />
<NativeMenuItem
Command="{Binding HelpAboutCommand}"
Gesture="cmd+b"
Header="About"
IsEnabled="{Binding AboutEnabled}" />
</NativeMenu>
</NativeMenuItem.Menu>
</NativeMenuItem>
<NativeMenuItem Header="Theme">
<NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem
Command="{Binding DefaultLightCommand}"
Header="Default Light"
IsEnabled="{Binding DefaultLightEnabled}" />
<NativeMenuItem
Command="{Binding DefaultDarkCommand}"
Header="Default Dark"
IsEnabled="{Binding DefaultDarkEnabled}" />
<NativeMenuItem
Command="{Binding FluentLightCommand}"
Header="Fluent Light"
IsEnabled="{Binding FluentLightEnabled}" />
<NativeMenuItem
Command="{Binding FluentDarkCommand}"
Header="Fluent Dark"
IsEnabled="{Binding FluentDarkEnabled}" />
</NativeMenu>
</NativeMenuItem.Menu>
</NativeMenuItem>
</NativeMenu>
</NativeMenu.Menu>
<Window 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:controls="clr-namespace:AvaloniaCoreRTDemo.Controls" 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">
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="_Exit" Command="{Binding FileExitCommand}"/>
</MenuItem>
<MenuItem Header="_Theme">
<MenuItem Header="Default Light" IsEnabled="{Binding DefaultLightEnabled}" Command="{Binding DefaultLightMethod}"/>
<MenuItem Header="Default Dark" IsEnabled="{Binding DefaultDarkEnabled}" Command="{Binding DefaultDarkMethod}"/>
<MenuItem Header="Fluent Light" IsEnabled="{Binding FluentLightEnabled}" Command="{Binding FluentLightMethod}"/>
<MenuItem Header="Fluent Dark" IsEnabled="{Binding FluentDarkEnabled}" Command="{Binding FluentDarkMethod}"/>
</MenuItem>
<MenuItem Header="_Help">
<MenuItem Header="_About" IsEnabled="{Binding AboutEnabled}" Command="{Binding HelpAboutMethod}"/>
</MenuItem>
</Menu>
<controls:MainControl/>
</DockPanel>
</Window>

View File

@ -1,48 +1,28 @@
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
namespace AvaloniaCoreRTDemo.Windows
{
private readonly Application? _app = Application.Current;
private MainControl MainController => this.GetControl<MainControl>("MainControl");
public MainWindow()
: this(default) { }
public MainWindow(IMainWindow? window)
public sealed partial class MainWindow : Window, IMainWindow
{
InitializeComponent(window);
#if DEBUG
this.AttachDevTools();
#endif
}
IThemeSwitch IMainWindow.ThemeSwitch => (IThemeSwitch)_app!;
IMainWindowState IMainWindow.Model => (IMainWindowState)this.MainController.DataContext!;
PixelPoint IMainWindow.Position => Utilities.GetWindowPosition(this);
Size IMainWindow.ClientSize => ClientSize;
Size? IMainWindow.FrameSize => FrameSize;
WindowState IMainWindow.State => WindowState;
private void InitializeComponent(IMainWindow? window)
{
AvaloniaXamlLoader.Load(this);
DataContext = new MainViewModel<MainWindow>(this);
if (window is not null)
public MainWindow()
{
this.MainController.Reload(window.Model);
WindowStartupLocation = WindowStartupLocation.Manual;
WindowState = window.State;
Position = window.Position;
FrameSize = window.FrameSize;
ClientSize = window.ClientSize;
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
this.DataContext = new MainViewModel<MainWindow>(this);
}
IThemeSwitch IMainWindow.ThemeSwitch => App.Current as IThemeSwitch;
}
}

View File

@ -0,0 +1,26 @@
<Window 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:controls="clr-namespace:AvaloniaCoreRTDemo.Controls" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="AvaloniaCoreRTDemo.Windows.MainWindowMacOS"
Width="640" Height="480" WindowStartupLocation="CenterScreen" Title="AvaloniaCoreRTDemo" Icon="avares://AvaloniaCoreRTDemo/Assets/app.ico" MinWidth="400" MinHeight="350">
<controls:MainControl/>
<NativeMenu.Menu>
<NativeMenu>
<NativeMenuItem Header="File">
<NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Header="Exit" Gesture="cmd+e" Command="{Binding FileExitCommand}"/>
</NativeMenu>
</NativeMenuItem.Menu>
</NativeMenuItem>
<NativeMenuItem Header="Theme">
<NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Header="Default Light" IsEnabled="{Binding DefaultLightEnabled}" Command="{Binding DefaultLightMethod}"/>
<NativeMenuItem Header="Default Dark" IsEnabled="{Binding DefaultDarkEnabled}" Command="{Binding DefaultDarkMethod}"/>
<NativeMenuItem Header="Fluent Light" IsEnabled="{Binding FluentLightEnabled}" Command="{Binding FluentLightMethod}"/>
<NativeMenuItem Header="Fluent Dark" IsEnabled="{Binding FluentDarkEnabled}" Command="{Binding FluentDarkMethod}"/>
</NativeMenu>
</NativeMenuItem.Menu>
</NativeMenuItem>
</NativeMenu>
</NativeMenu.Menu>
</Window>

View File

@ -0,0 +1,28 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using AvaloniaCoreRTDemo.Interfaces;
using AvaloniaCoreRTDemo.Windows.ViewModels;
namespace AvaloniaCoreRTDemo.Windows
{
public partial class MainWindowMacOS : Window, IMainWindow
{
public MainWindowMacOS()
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
this.DataContext = new MainViewModel<MainWindowMacOS>(this);
}
IThemeSwitch IMainWindow.ThemeSwitch => App.Current as IThemeSwitch;
}
}

View File

@ -1,56 +1,54 @@
using System.Runtime.InteropServices;
using System;
using System.Runtime.InteropServices;
using Avalonia.Media.Imaging;
namespace AvaloniaCoreRTDemo.Windows.ViewModels;
using ReactiveUI;
internal record SystemDetail(string Key, string Value);
[ViewModel]
internal sealed partial class AboutViewModel
namespace AvaloniaCoreRTDemo.Windows.ViewModels
{
private readonly Bitmap _computerImage;
private readonly bool _darkTheme;
public Bitmap ComputerImage => _computerImage;
public IReadOnlyList<SystemDetail> SystemDetails { get; } =
[
new SystemDetail("Number of Cores", Environment.ProcessorCount.ToString()),
new SystemDetail("OS", RuntimeInformation.OSDescription),
new SystemDetail("OS Arch", RuntimeInformation.OSArchitecture.ToString()),
new SystemDetail("OS Version", Environment.OSVersion.ToString()),
new SystemDetail("Computer", Environment.MachineName),
new SystemDetail("User", Environment.UserName),
new SystemDetail("System Path", Environment.SystemDirectory),
new SystemDetail("Current Path", Environment.CurrentDirectory),
new SystemDetail("Process Arch", RuntimeInformation.ProcessArchitecture.ToString()),
new SystemDetail("Runtime Name", RuntimeInformation.FrameworkDescription),
new SystemDetail("Runtime Path", RuntimeEnvironment.GetRuntimeDirectory()),
new SystemDetail("Runtime Version", RuntimeEnvironment.GetSystemVersion()),
new SystemDetail("Framework Version", Environment.Version.ToString())
];
private string ComputerImageName
internal sealed class AboutViewModel : ReactiveObject
{
get
private readonly IBitmap _computerImage;
private readonly Boolean _darkTheme;
public IBitmap ComputerImage => _computerImage;
public static String NCores => Environment.ProcessorCount.ToString();
public static String OS => RuntimeInformation.OSDescription;
public static String OSArch => RuntimeInformation.OSArchitecture.ToString();
public static String OSVersion => Environment.OSVersion.ToString();
public static String ComputerName => Environment.MachineName;
public static String UserName => Environment.UserName;
public static String SystemPath => Environment.SystemDirectory;
public static String CurrentPath => Environment.CurrentDirectory;
public static String ProcessArch => RuntimeInformation.ProcessArchitecture.ToString();
public static String RuntimeName => RuntimeInformation.FrameworkDescription;
public static String RuntimePath => RuntimeEnvironment.GetRuntimeDirectory();
public static String RuntimeVersion => RuntimeEnvironment.GetSystemVersion();
public static String FrameworkVersion => Environment.Version.ToString();
private String ComputerImageName
{
if (Utilities.IsWindows)
return !_darkTheme ? "windows.png" : "windows_d.png";
if (Utilities.IsOSX)
return !_darkTheme ? "macos.png" : "macos_d.png";
return !_darkTheme ? "linux.png" : "linux_d.png";
get
{
if (Utilities.IsWindows)
return !this._darkTheme ? "windows.png" : "windows_d.png";
else if (Utilities.IsOSX)
return !this._darkTheme ? "macos.png" : "macos_d.png";
else
return !this._darkTheme ? "linux.png" : "linux_d.png";
}
}
public AboutViewModel(Boolean darkTheme)
{
this._darkTheme = darkTheme;
this._computerImage = Utilities.GetImageFromResources(this.ComputerImageName);
}
~AboutViewModel()
{
this._computerImage.Dispose();
}
}
public AboutViewModel(bool darkTheme)
: this()
{
_darkTheme = darkTheme;
_computerImage = Utilities.GetImageFromResources(ComputerImageName);
}
~AboutViewModel()
{
_computerImage.Dispose();
}
}

View File

@ -1,86 +0,0 @@
using Avalonia.Controls;
using AvaloniaCoreRTDemo.Interfaces;
namespace AvaloniaCoreRTDemo.Windows.ViewModels;
[ViewModel]
internal abstract partial class ApplicationModelBase
{
private readonly IThemeSwitch _themeSwitch;
[Property]
private bool _aboutEnabled = true;
[Property]
private bool _defaultLightEnabled;
[Property]
private bool _defaultDarkEnabled;
[Property]
private bool _fluentLightEnabled;
[Property]
private bool _fluentDarkEnabled;
public ApplicationModelBase(IThemeSwitch themeSwitch)
: this()
{
_themeSwitch = themeSwitch;
InitializeTheme(themeSwitch.Current);
}
[Command]
protected abstract void HelpAbout();
[Command]
protected abstract void DefaultLight();
[Command]
protected abstract void DefaultDark();
[Command]
protected abstract void FluentLight();
[Command]
protected abstract void FluentDark();
protected async void RunHelpAbout(Window currentWindow)
{
if (AboutEnabled)
try
{
AboutEnabled = false;
await new AboutWindow(IsDarkTheme(_themeSwitch.Current)).ShowDialog(currentWindow);
}
finally
{
AboutEnabled = true;
}
}
protected void SetTheme(ApplicationTheme theme)
{
InitializeTheme(theme);
_themeSwitch.ChangeTheme(theme);
}
[Command]
private void FileExit() => Environment.Exit(0);
private void InitializeTheme(ApplicationTheme theme)
{
DefaultLightEnabled = theme != ApplicationTheme.SimpleLight;
DefaultDarkEnabled = theme != ApplicationTheme.SimpleDark;
FluentLightEnabled = theme != ApplicationTheme.FluentLight;
FluentDarkEnabled = theme != ApplicationTheme.FluentDark;
}
private static bool IsDarkTheme(ApplicationTheme? theme) =>
theme switch
{
ApplicationTheme.SimpleDark => true,
ApplicationTheme.FluentDark => true,
_ => false,
};
}

View File

@ -1,26 +1,72 @@
using Avalonia.Controls;
using AvaloniaCoreRTDemo.Interfaces;
using System;
using System.Reactive;
namespace AvaloniaCoreRTDemo.Windows.ViewModels;
using Avalonia.Controls;
internal sealed class MainViewModel<TWindow> : ApplicationModelBase
where TWindow : Window, IMainWindow
using ReactiveUI;
namespace AvaloniaCoreRTDemo.Windows.ViewModels
{
private readonly TWindow _window;
public MainViewModel(TWindow window)
: base(window.ThemeSwitch)
internal sealed class MainViewModel<TWindow> : MainViewModelBase
where TWindow : Window, IMainWindow
{
_window = window;
private readonly TWindow _window;
private Boolean _defaultLightEnable = true;
private Boolean _defaultDarkEnable = true;
private Boolean _fluentLightEnable = true;
private Boolean _fluentDarkEnable = true;
public Boolean DefaultLightEnabled
{
get => this._defaultLightEnable;
set => this.RaiseAndSetIfChanged(ref this._defaultLightEnable, value);
}
public Boolean DefaultDarkEnabled
{
get => this._defaultDarkEnable;
set => this.RaiseAndSetIfChanged(ref this._defaultDarkEnable, value);
}
public Boolean FluentLightEnabled
{
get => this._fluentLightEnable;
set => this.RaiseAndSetIfChanged(ref this._fluentLightEnable, value);
}
public Boolean FluentDarkEnabled
{
get => this._fluentDarkEnable;
set => this.RaiseAndSetIfChanged(ref this._fluentDarkEnable, value);
}
public ReactiveCommand<Unit, Unit> FileExitCommand { get; }
public MainViewModel(TWindow window)
: base(window.ThemeSwitch)
{
this._window = window;
this.FileExitCommand = ReactiveCommand.Create(RunFileExit);
this.ChangeTheme(window.ThemeSwitch.Current);
}
public void DefaultLightMethod() => this.ChangeTheme(ApplicationTheme.DefaultLight);
public void DefaultDarkMethod() => this.ChangeTheme(ApplicationTheme.DefaultDark);
public void FluentLightMethod() => this.ChangeTheme(ApplicationTheme.FluentLight);
public void FluentDarkMethod() => this.ChangeTheme(ApplicationTheme.FluentDark);
public override void HelpAboutMethod() => base.RunHelpAbout(this._window);
private void RunFileExit()
=> Environment.Exit(0);
private void ChangeTheme(ApplicationTheme theme)
{
this.DefaultLightEnabled = theme != ApplicationTheme.DefaultLight && theme != ApplicationTheme.FluentLight;
this.DefaultDarkEnabled = theme != ApplicationTheme.DefaultDark && theme != ApplicationTheme.FluentDark;
this.FluentLightEnabled = theme != ApplicationTheme.FluentLight;
this.FluentDarkEnabled = theme != ApplicationTheme.FluentDark;
this._window.ThemeSwitch?.ChangeTheme(theme);
}
}
protected override void HelpAbout() => RunHelpAbout(_window);
protected override void DefaultLight() => SetTheme(ApplicationTheme.SimpleLight);
protected override void DefaultDark() => SetTheme(ApplicationTheme.SimpleDark);
protected override void FluentLight() => SetTheme(ApplicationTheme.FluentLight);
protected override void FluentDark() => SetTheme(ApplicationTheme.FluentDark);
}

View File

@ -0,0 +1,49 @@
using System;
using Avalonia.Controls;
using AvaloniaCoreRTDemo.Interfaces;
using ReactiveUI;
namespace AvaloniaCoreRTDemo.Windows.ViewModels
{
internal abstract class MainViewModelBase : ReactiveObject
{
private readonly IThemeSwitch _themeSwitch;
private Boolean _aboutEnable = true;
public Boolean AboutEnabled
{
get => this._aboutEnable;
set => this.RaiseAndSetIfChanged(ref this._aboutEnable, value);
}
public MainViewModelBase(IThemeSwitch window)
=> this._themeSwitch = window;
public abstract void HelpAboutMethod();
protected async void RunHelpAbout(Window currentWindow)
{
if (this.AboutEnabled)
try
{
this.AboutEnabled = false;
await new AboutWindow(IsDarkTheme(this._themeSwitch.Current)).ShowDialog(currentWindow);
}
finally
{
this.AboutEnabled = true;
}
}
private static Boolean IsDarkTheme(ApplicationTheme? theme)
=> theme switch
{
ApplicationTheme.DefaultDark => true,
ApplicationTheme.FluentDark => true,
_ => false,
};
}
}

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!--<add key="avalonia" value="https://nuget.avaloniaui.net/repository/avalonia-all/index.json" />-->
<add key="dotnet7" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json" />
<add key="dotnet8" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8/nuget/v3/index.json" />
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>

48
src/rd.xml Normal file
View File

@ -0,0 +1,48 @@
<Directives>
<Application>
<!-- main app assembly provides types which needs to be reflected upon -->
<Assembly Name="AvaloniaCoreRTDemo" Dynamic="Required All"></Assembly>
<!-- these are needed when you show images and draw text -->
<Assembly Name="Avalonia.Animation">
<Type Name="Avalonia.Animation.Easings.QuadraticEaseIn" Dynamic="Required All" />
<Type Name="Avalonia.Animation.Easings.QuadraticEaseOut" Dynamic="Required All" />
<Type Name="Avalonia.Animation.Easings.CubicEaseOut" Dynamic="Required All" />
<Type Name="Avalonia.Animation.Easings.LinearEasing" Dynamic="Required All" />
</Assembly>
<Assembly Name="Avalonia.Themes.Default" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Visuals" Dynamic="Required All">
<Type Name="Avalonia.Media.SolidColorBrush" Dynamic="Required All" />
</Assembly>
<Assembly Name="SkiaSharp" Dynamic="Required All"></Assembly>
<!-- To support Fluent themes trimming the final assembly we need to add this entry -->
<Assembly Name="Avalonia.Themes.Fluent" Dynamic="Required All"></Assembly>
<!-- Not known if and when you need these:
<Assembly Name="Avalonia.Controls" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Base" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Interactivity" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Layout" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Markup" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Markup.Xaml" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Styling" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.DesktopRuntime" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.DesignerSupport" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Diagnostics" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Dialogs" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Input" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Logging.Serilog" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.OpenGL" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Desktop" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Direct2D1" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.ReactiveUI" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Skia" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Win32" Dynamic="Required All"></Assembly>
<Assembly Name="ReactiveUI" Dynamic="Required All"></Assembly>
<Assembly Name="System.Reactive" Dynamic="Required All"></Assembly>
<Assembly Name="Splat" Dynamic="Required All"></Assembly>
-->
</Application>
</Directives>

View File

@ -1,2 +1,2 @@
del src\packages.lock.json
dotnet publish -r win-x64 -c Release /p:RestoreLockedMode=true
dotnet publish -r win-x64 -c release /p:RestoreLockedMode=true /p:TrimLink=true --self-contained

View File

@ -4,7 +4,10 @@ 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
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
dotnet publish -r osx-x64 -c release /p:RestoreLockedMode=true -t:BundleApp /p:TrimLink=true --self-contained
rm -rf src/bin/x64/Release/net6.0/osx-x64/publish/Assets/
strip src/bin/x64/Release/net6.0/osx-x64/publish/AvaloniaCoreRTDemo.app/Contents/MacOS/AvaloniaCoreRTDemo
rm -rf src/bin/x64/Release/net6.0/osx-x64/publish/AvaloniaCoreRTDemo.app/Contents/MacOS/Assets/
rm src/bin/x64/Release/net6.0/osx-x64/publish/AvaloniaCoreRTDemo.app/Contents/MacOS/AvaloniaCoreRTDemo.runtimeconfig.json
rm src/bin/x64/Release/net6.0/osx-x64/publish/AvaloniaCoreRTDemo.app/Contents/MacOS/AvaloniaCoreRTDemo.pdb
rm src/bin/x64/Release/net6.0/osx-x64/publish/AvaloniaCoreRTDemo.app/Contents/MacOS/AvaloniaCoreRTDemo.deps.json

View File

@ -1,5 +1,6 @@
#!/bin/bash
rm -f src/packages.lock.json
dotnet publish -r linux-x64 -c Release /p:RestoreLockedMode=true
cd src/bin/Release/net7.0/linux-x64/publish
dotnet publish -r linux-x64 -c release /p:RestoreLockedMode=true /p:TrimLink=true --self-contained
cd src/bin/x64/Release/net6.0/linux-x64/publish
cp AvaloniaCoreRTDemo AvaloniaCoreRTDemo.bin
strip AvaloniaCoreRTDemo.bin