dullwhaleのメモ帳

何度も同じことを調べなくてよいように...

Windows App SDK(WinUI3)でコンポーネントをUser Controlとして作る

Webのフロントエンドのコンポーネントに相当するWinUI3のパーツはCustom ControlかUser Controlである。 Custom Controlはより低レベルの概念であり、独自の動作と描画ロジックを持てる。 対してUser Controlは既存のコントロール(UIパーツ)の組み合わせであり、フロントエンド用語のコンポーネントにより近いと思われる。

まずはUser Controlとして実装することを考え、User Controlで実現不可能な場合だけCustom Controlとして実装することを検討すると良い。 この記事では以降User Controlにだけ言及する。 また、実用性よりも分かりやすさを優先し、この記事では機能を抑えたUser Controlを作成する。

最低限のUser Controlを作成する

ここではStackPanel内にTextBoxとTextBlockを並べた塊をUser Controlとして作成する。 TextBoxに入力されている文字列が変化したことをイベントハンドラでキャッチし、TextBlockに反映する。

User Controlの実装

User Controlは名前通りWindows.UI.Xaml.Controls.UserControlというクラスを継承して実装する。 公式のドキュメントはこれ

UserControl クラス (Windows.UI.Xaml.Controls) - Windows UWP applications | Microsoft Learn

Visual Stdioの機能で作成する場合は「新しい項目の追加」ダイアログから「ユーザーコントロール(WinUI 3)」を選択する。 ここではComponents/ ディレクトリ配下に作成し、名前はFormTextInputとする。

生成された.xamlファイルと.xaml.csファイルを少し修正し、以下のようにする。

Components/FormTextInput.xaml

<?xml version="1.0" encoding="utf-8"?>
<UserControl
    x:Class="foo.Components.FormTextInput"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:foo.Components"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <StackPanel Orientation="Vertical">
        <TextBox x:Name="InputTextBox" TextChanged="InputTextChanged" />
        <TextBlock x:Name="Message"/>
    </StackPanel>
</UserControl>

Components/FormTextInput.xaml.cs

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

namespace foo.Components
{
  public sealed partial class FormTextInput : UserControl
  {
    public FormTextInput()
    {
      this.InitializeComponent();
    }

    // TextBoxの文字が変更された際に発火するイベントハンドラ
    private void InputTextChanged(object sender, TextChangedEventArgs e)
    {
      Message.Text = InputTextBox.Text;
    }
  }
}

x:Nameを設定して、.xaml.cs側でインスタンスに名前でアクセスできるようにしている。 実用性はともかく、これでFormTextInputというUser Controlが作成できた。

作成したUser Controlの使い方

作成したUser Controlを、利用したいXAML中で名前空間としてインポートする。 例えば、以下に示すBarPageではxmlns:u="using:foo.Components"という記述より、u:で参照できるようになる。

補足説明:xmlnsについて xmlnsXMLにおける用語としての名前空間を定義する。 これはXAMLMicrosoft独特の仕様ではなく、本家のXMLの仕様である。

例えば次のように記述すると、localという名前空間が定義される。

xmlns:local="using:foo.Components"

すると、そのXMLでは接頭辞を用いてlocal:Bazのように参照できる。

当然、次のように記述すれば、a:Bazのように参照できる。

xmlns:a="using:foo.Components"

BarPage.xaml

<?xml version="1.0" encoding="utf-8"?>
<Page
    x:Class="foo.BarPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    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:u="using:foo.Components"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<!-- 途中略 -->
        <u:FormTextInput />
<!-- 以下略 -->

User Controlをもっと実用的に作る

この記事では単純なUser Controlを作成したが、実際のアプリケーションにおいてパーツとして再利用するためにはもう少し作りこみが必要だろう。 記事のスコープを狭めるため、発展的な内容については別の記事にメモする。