0. 前置き
LXC に .Net SDK をインストールし、C# と VB を使用してコンソールアプリのスケルトンを実行します。
そのあと、Avalonia のテストプログラムを C# で作成し、Xvfb + VNC で実行します。
1. .Net SDK のインストール
LXC を使用する場合は、該当コンテナにログイン (or アタッチ) してから操作する。
1-1. .Net SDK 9.0 をインストールする。(464 MB)
$ su1-2. C# の動作確認をする。(コンソールアプリ)
# dnf install -y epel-release
# dnf install -y dotnet-sdk-9.0
# dotnet --version
# exit
9.0.109
$
$ dotnet new console -lang C# -o ./ConsoleCS/ # -lang には {C# F# VB} を指定する。(省略すると C# になる)1-3. VB の動作確認をする。(コンソールアプリ)
$ cat ./ConsoleCS/Program.cs
$ dotnet run --project ./ConsoleCS/ConsoleCS.csprojMain がエントリポイントだが、Main を省略可能。
// See https://aka.ms/new-console-templete for more information Console.WriteLine("Hello, World!");
$ ls -lhog ./ConsoleCS/bin/Debug/net9.0/
Hello, World!
total 120K -rwxr-xr-x. 1 91K Sep 4 20:39 ConsoleCS -rw-r--r--. 1 397 Sep 4 20:39 ConsoleCS.deps.json -rw-r--r--. 1 4.5K Sep 4 20:39 ConsoleCS.dll -rw-r--r--. 1 11K Sep 4 20:39 ConsoleCS.pdb -rw-r--r--. 1 257 Sep 4 20:39 ConsoleCS.runtimeconfig.json
$ dotnet new console -lang VB -o ./ConsoleVB/
$ cat ./ConsoleVB/Program.vb
$ dotnet run --project ./ConsoleVB/ConsoleVB.vbprojMain がエントリポイント。ファイル名は関係しない。Main が複数存在するとエラーになる。
Imports System Module Program Sub Main(args As String()) Console.WriteLine("Hello World!") End Sub End Module
$ ls -lhog ./ConsoleVB/bin/Debug/net9.0/
Hello World!
total 120 -rwxr-xr-x. 1 91K Sep 4 20:49 ConsoleVB -rw-r--r--. 1 397 Sep 4 20:49 ConsoleVB.deps.json -rw-r--r--. 1 4.5K Sep 4 20:49 ConsoleVB.dll -rw-r--r--. 1 11K Sep 4 20:49 ConsoleVB.pdb -rw-r--r--. 1 257 Sep 4 20:49 ConsoleVB.runtimeconfig.json
2. Avalonia を実行
2-1. X の環境を用意する。
実行環境はこちら (KVM で LXC) とこちら (LXC で GUI) を参照。2-2. Avalonia のテンプレートで C# のプロジェクトを作成する。
GUI なしで Avalonia を実行すると、例外「XOpenDisplay failed」により異常終了する。
$ Xvfb :1 -screen 0 640x480x24 & # Xvfb を用意する。(DISPLAY=:1.0 をここで用意)
$ x11vnc -display :1.0 -rfbport 5901 -nopw & # X を VNC サーバとしてリンクする。
$ DISPLAY=:1.0 openbox & # ウィンドウマネージャを起動する。(これがないと枠が表示されない)
GUI 環境を終了させるには以下のようにする。
$ ps ax | grep 'Xvfb :1' 3001 pts/5 S 0:01 Xvfb :1 -screen 0 640x480x24 ← これ 3002 pts/5 S+ 0:00 grep --color=auto Xvfb :1 $ kill 3001
$ dotnet new install Avalonia.Templates2-3. Avalonia のプロジェクトを実行する。(インタープリタ)
削除するには dotnet new uninstall Avalonia.Templates を実行する。
$ dotnet new avalonia.app -lang C# -o ./AvaCS/
$ dotnet list ./AvaCS/AvaCS.csproj package
[net9.0]: Top-level Package Requested Resolved > Avalonia 11.3.5 11.3.5 > Avalonia.Desktop 11.3.5 11.3.5 > Avalonia.Diagnostics 11.3.5 11.3.5 > Avalonia.Fonts.Inter 11.3.5 11.3.5 > Avalonia.Themes.Fluent 11.3.5 11.3.5
$ DISPLAY=:1.0 dotnet run --project ./AvaCS/AvaCS.csproj # 作成した Avalonia プロジェクトを実行する。2-4. Avalonia の実行ファイルを作成する。
Windows から TightVNC(Viewer) で接続する。
⇓
− □ × >_ Windows PowerShell × + | ∨
Windows PowerShell Copyright (C) Microsoft Corporation. All rights reserved. 新機能と改善のために最新の PowerShell をインストールしてください!https://aka.ms/PSWindows PS C:\> # TightVNC Viewer を起動する PS C:\> & "C:\Program Files\TightVNC\tvnviewer.exe" 192.168.11.20:1159 ⏎ PS C:\> exit ⏎
.Net SDK (6 以上) では 32bit の実行ファイルを作成することができない。2-5. Linux 用実行ファイルを X で実行する。
Windows11 から 32bit 版が存在しないため、今後問題になることはないと予測される。
(古い Linux では問題が起きるかもしれない)
実行ファイルを生成 (Linux 用)
$ dotnet publish ./AvaCS/AvaCS.csproj -c Release -r linux-x64 --self-contained true \
/p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true \
-o ./publishdir/
実行ファイルを生成 (Windows 用)
$ dotnet publish ./AvaCS/AvaCS.csproj -c Release -r win-x64 --self-contained true \
/p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true \
-o ./publishdir/
$ LANG=c tree ./publishdir/
./publishdir/ |-- AvaCS ← Linux 用 (ELF バイナリ) |-- AvaCS.exe ← Windows 用 (実行ファイル) `-- AvaCS.pdb ← デバッグ情報(不要) 0 directories, 3 files
$ DISPLAY=:1.0 ./publishdir/AvaCS
→ 実行画面は上記 2-3 と同じ。
3. プログラムを作成してみる
3-1. 変更前のプログラムを確認。(初期のひな形プログラム)
$ cat ./AvaCS/MainWindow.axaml3-2. テキストを TextBlock にしておく
画面の部品構成を定義するファイル
<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" d:DesignWidth="800" d:DesignHeight="450" x:Class="AvaCS.MainWindow" Title="AvaCS"> Welcome to Avalonia! </Window>
$ cat ./AvaCS/MainWindow.axaml.cs
画面部品のアクションを記述するファイル
using Avalonia.Controls; namespace AvaCS; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } }
他のパーツと混在させるときにややこしくなるのを防ぐ。3-3. ボタンを追加
< ./AvaCS/MainWindow.axaml >
<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" d:DesignWidth="800" d:DesignHeight="450" x:Class="AvaCS.MainWindow" Title="AvaCS"> <TextBlock Text="Welcome to Avalonia!" /> </Window>
ブロック <Window> は、一度に複数の要素を内包できない。3-4. MessageBox を追加
複数を一つの要素として扱うために <StackPanel> でまとめる。
< ./AvaCS/MainWindow.axaml >
ここではボタンにアクション Click= として OnButtonClick を指定している。
<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" d:DesignWidth="800" d:DesignHeight="450" x:Class="AvaCS.MainWindow" Title="AvaCS"> <StackPanel> <TextBlock Text="Welcome to Avalonia!" /> <Button Content="Click me." Width="80" Height="32" Click="OnButtonClick" /> </StackPanel> </Window>
その場合は対応する名前の処理を *.cs に記述しなければならない。(記述しないとエラーになる)
< ./AvaCS/MainWindow.axaml.cs >
using Avalonia.Controls; using Avalonia.Interactivity; // RoutedEventArgs を使う namespace AvaCS; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void OnButtonClick(object? sender, RoutedEventArgs e) { // ボタンの処理をここに記述する (sender as Button)?.SetValue(ContentProperty, "Clicked"); } }
プロジェクトに MessageBox を追加する。3-5. プロジェクトを実行する。(インタープリタ)
$ dotnet add ./AvaCS/AvaCS.csproj package MessageBox.Avalonia
< ./AvaCS/MainWindow.axaml.cs >
ここで使用している msgBox.ShowAsync() は処理をブロックせず、MainWindow をクリックすると後ろに隠れてしまうので注意。
using Avalonia.Controls; using Avalonia.Interactivity; // RoutedEventArgs を使う using MsBox.Avalonia; // MessageBoxManager を使う using MsBox.Avalonia.Enums; // ButtonEnum を使う using System; // Console を使う namespace AvaCS; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private async void OnButtonClick(object? sender, RoutedEventArgs e) { // ボタンの処理をここに記述する //(sender as Button)?.SetValue(ContentProperty, "Clicked");var msgBox = MessageBoxManager.GetMessageBoxStandard( "タイトル", "メッセージ", ButtonEnum.OkCancel, MsBox.Avalonia.Enums.Icon.Question); this.IsEnabled = false; // MainWindow のアクションを無効にする var result = await msgBox.ShowAsync(); this.IsEnabled = true; // MainWindow のアクションを有効にする if (result == ButtonResult.Ok) { Console.WriteLine("OK Clicked."); } } }
Windows の MessageBox のような動作をさせるには作り込みが必要。
$ DISPLAY=:1.0 dotnet run --project ./AvaCS/AvaCS.csproj
Windows から TightVNC(Viewer) で接続する。
⇓
− □ × >_ Windows PowerShell × + | ∨
Windows PowerShell Copyright (C) Microsoft Corporation. All rights reserved. 新機能と改善のために最新の PowerShell をインストールしてください!https://aka.ms/PSWindows PS C:\> # TightVNC Viewer を起動する PS C:\> & "C:\Program Files\TightVNC\tvnviewer.exe" 192.168.11.20:1159 ⏎ PS C:\> exit ⏎