この記事は公開から3年以上経過しています。
WPFでお馴染みのXAMLでGUIアプリケーションを作成できるフレームワークAvaloniaを使い、Linux上で実行可能なGUIデスクトップアプリケーションをVisual Studio Codeで開発する方法を紹介します。
本記事はLinuxを対象としていますが、AvaloniaはマルチプラットフォームなのでLinux/Windows/Macでも利用可能です。
.NET 5.0 SDKが導入済、VSCodeにC#拡張が導入済である前提です。
手順
-
以下のコマンドで作業フォルダを作成し、その中にAvaloniaのテンプレートをダウンロードする。
mkdir /tmp/avalonia && cd $_ git clone --depth 1 https://github.com/AvaloniaUI/avalonia-dotnet-templates
-
ダウンロードしたAvaloniaのテンプレートを以下のコマンドでインストールする。
dotnet new --install avalonia-dotnet-templates
インストールが成功すると、以下のようにインストールされたパッケージの一覧が表示される。
次のパッケージがインストールされます: /tmp/avalonia/avalonia-dotnet-templates 成功: /tmp/avalonia/avalonia-dotnet-templatesにより次のテンプレートがインストールされました。 テンプレート名 短い名前 言語 タグ ---------------------------- ------------------------- ------- --------------------------- Avalonia .NET Core App avalonia.app [C#],F# ui/xaml/avalonia/avaloniaui Avalonia .NET Core MVVM App avalonia.mvvm [C#],F# ui/xaml/avalonia/avaloniaui Avalonia Resource Dictionary avalonia.resource ui/xaml/avalonia/avaloniaui Avalonia Styles avalonia.styles ui/xaml/avalonia/avaloniaui Avalonia TemplatedControl avalonia.templatedcontrol [C#] ui/xaml/avalonia/avaloniaui Avalonia UserControl avalonia.usercontrol [C#],F# ui/xaml/avalonia/avaloniaui Avalonia Window avalonia.window [C#],F# ui/xaml/avalonia/avaloniaui
-
以下のコマンドで開発を行うプロジェクト用のディレクトリを作成してカレントディレクトリを移動する。
mkdir HelloAvalonia && cd $_
-
以下のコマンドで
Avalonia .NET Core App
のテンプレートプロジェクトを作成する。dotnet new avalonia.app
プロジェクトが作成されると、以下のように表示される。
テンプレート "Avalonia .NET Core App" が正常に作成されました。
-
手順3で作成したディレクトリをVSCodeで開く。コマンドで開く場合は以下のとおり。
code ./
-
VSCodeに以下のメッセージが表示されたら
Yes
を押下してビルド/デバッグ用のアセット(.vscode
のlaunch.json
とtask.json
)を追加する(表示されない場合はF1
キーを押下してコマンドパレットから.net generate assets for build and debug
コマンドを実行)。ここまでで作成されたファイル群は以下のとおり。
-
VSCodeで
F5
キーを押下してプログラムを実行すると、以下のようなウィンドウが表示される。
サンプルソースコード
折角なので、Avaloniaを使って入力テキストをBASE64エンコードするだけの簡単なMVVMアプリケーションを作成してみました。
MainWindow.axaml(拡張子がaxaml
であることに注意)
<Window
x:Class="HelloAvalonia.MainWindow"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="Convert to BASE64"
Width="500"
Height="400"
d:DesignHeight="450"
d:DesignWidth="800"
FontFamily="Sans"
mc:Ignorable="d">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Text="{Binding InputText}" />
<GridSplitter
Grid.Row="1"
Height="5"
HorizontalAlignment="Stretch" />
<TextBox
Grid.Row="2"
IsReadOnly="True"
Text="{Binding OutputText, Mode=OneWay}" />
<Grid Grid.Row="3" Margin="0,5,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button
Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Command="{Binding ConvertCmd}"
Content="Convert to BASE64" />
</Grid>
</Grid>
</Window>
MainWindow.axaml.cs
using System;
using System.Windows;
using System.Windows.Input;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Interactivity;
namespace HelloAvalonia
{
/// <summary>
/// View
/// </summary>
public partial class MainWindow : Window
{
private readonly ViewModel _viewModel;
private readonly Model _model;
public MainWindow()
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
_model = new Model();
_viewModel = new ViewModel(_model);
DataContext = _viewModel;
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
/// <summary>
/// ViewModel
/// </summary>
public sealed class ViewModel : NotificationBase
{
private readonly Model _model;
public string InputText
{
get => _model.InputText;
set
{
if (_model.InputText != value)
{
_model.InputText = value;
ConvertCmd.NotifyChanged();
}
}
}
public string OutputText { get; private set; } = string.Empty;
public RelayCommand ConvertCmd { get; }
public ViewModel(Model model)
{
_model = model;
ConvertCmd = new RelayCommand(
(_) => _model.InputText.Length > 0,
(_) =>
{
_model.ConvertText();
if (OutputText != _model.OutputText)
{
OutputText = _model.OutputText;
NotifyPropChanged(nameof(OutputText));
}
}
);
}
}
/// <summary>
/// Model
/// </summary>
public sealed class Model
{
public string InputText { get; set; } = string.Empty;
public string OutputText { get; private set; } = string.Empty;
public void ConvertText()
{
var bin = Encoding.UTF8.GetBytes(InputText);
OutputText = Convert.ToBase64String(bin);
}
}
public abstract class NotificationBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public bool SetProp<T>(ref T obj, T value, [CallerMemberName] string? propName = null)
{
if (EqualityComparer<T>.Default.Equals(obj, value))
return false;
obj = value;
NotifyPropChanged(propName);
return true;
}
public void NotifyPropChanged([CallerMemberName] string? propName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
public sealed class RelayCommand : ICommand
{
private readonly Func<object?, bool> _fncCanExecute;
private readonly Action<object?> _subExecute;
public event EventHandler? CanExecuteChanged;
public RelayCommand(Func<object?, bool> canExecute, Action<object?> execute)
{
_fncCanExecute = canExecute;
_subExecute = execute;
}
public bool CanExecute(object? parameter) => _fncCanExecute(parameter);
public void Execute(object? parameter) => _subExecute(parameter);
public void NotifyChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}
実行結果
上図のように、Linuxで簡単にGUIアプリケーションが作成できました。
ちなみに、今回AvaloniaをLinuxで使ってみての率直な感想はWPFと比べるとまだまだ未成熟な部分も多く本気で使おうとするとハマる要素が多々あるという印象でしたが、WPF/MVVMに慣れていればLinuxで簡単にGUIプログラミングができるAvaloniaは非常に有用なフレームワークではないかと思います。
参考ウェブサイトなど
以上です。