XAMLで始めるWPF入門:過去一シンプルなユーザーコントロールのサンプルコード。

コンピュータ

個人的にWPFの学習の最終段階はカスタムコントロールだと思っていましたが、汎用的なGUIコントロールを使う場面は、個人開発では意外と少なく、それに労力を払うより、ユーザーコントロールでソースコードを分割するぐらいがちょうど良い感じがします。

カスタムコントロールの場合、使い方さえ知っていれば、使うことが出来る汎用コントロールの私家版みたいな物で、汎用性を考えてコードを書く必要があります。ユーザーコントロールは、カスタムコントロールと似ている部分はありますが、振る舞いなどのコードをアプリケーションに合わせてカスタマイズすることが前提の使い方に成ります。

使う側としてユーザーコントロール方がハードルが高いことに成りますが、作る側としてカスタムコントロールは超高難易度に成ります。ユーザーコントロールが対象となるアプリケーションの事だけ考えてコードを書けば良いですが、カスタムコントロールは多くのアプリケーションを想定したコードを求められます。

サンプルコード

ファイル名:MiniLabel.cs

using System.Windows;
using System.Windows.Controls;

namespace UserControlSample;

public class MiniLabel : UserControl
{
    // MiniLabelにはテキストブロックを配置
    private readonly TextBlock _textBlock;

    public MiniLabel()
    {
        // テキストブロックを生成
        _textBlock = new TextBlock();
        // MiniLabelのContentにセット
        Content = _textBlock;
    }

    // TextをDPとしてXAMLでバインド可能にしている。
    // TextPropertyの変更イベントで新しい値を_textBlock.Textに代入している。
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register(
            nameof(Text),
            typeof(string),
            typeof(MiniLabel),
            new FrameworkPropertyMetadata(string.Empty, (d, e) =>
                ((MiniLabel)d)._textBlock.Text = (string)e.NewValue));
    
    // Textプロパティ
    public string Text
    {
        get => (string)GetValue(TextProperty);
        set => SetValue(TextProperty, value);
    }
}

UserControlを継承したMiniLabelがあります。
MiniLabelはフィールドとしてTextBlockを保持していて、コンストラクタでTextBlockのオブジェクトを生成し、MiniLabelのコンテンツにしているので、レイアウト的にもMiniLabel上にTextBlockが配置されることに成ります。ただ、MiniLabelの親クラスのUserControlはコンテナで、見えるのはTextBlockのみとなります。

MiniLabelで文字を表示するためにTextプロパティを定義します。これは普通のクラスのプロパティ(CLR)です。
そしてTextPropertyという名前のプロパティがあり、こちらは依存関係プロパティ(DP)で、TextプロパティをXAML側からバインド可能にしています。

Textプロパティ(CLR)ではTextPropertyに値をセットしたり、取得していることが確認できます。

TextProperty(DP)では、変更イベントで、値をTextBlock.Textに代入しています。

大まかなデータの流れは

Text(CLR) ⇒ TextProperty(DP) ⇒ _textBlock.Text

とつながっており、DPを経由することでXAMLでTextプロパティがバインド可能にしている点を除けば、普通のC#のコードに成ります。

以上がUserControlの基本的なコントロールの配置のサンプルに成ります。

ただ、このままでは、機能を限定したTextBlockとなってしまいます。コントロールで発生するイベントを処理するコードビハインドを記述することで、固有の振る舞いをするユーザーコントロールとして 機能し始めます。

複数のコントロールを配置することも出来ます。コントロール以外のフィールドで情報を持たせることも可能です。
UserControlを継承し、プロパティをバインド可能にする処理以外は、普通のC#のクラスと同じと考えて差支えないと思います。

・ユーザーコントロールMiniLabelを使う側のXAMLは以下の様になります。

ファイル名:MainWindow.xaml

<Window x:Class="UserControlSample.MainWindow"
        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:local="clr-namespace:UserControlSample"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel Margin="12">
        <local:MiniLabel Text="こんにちは、MiniLabel!"/>
    </StackPanel>
</Window>

MiniLabelというコントロールを配置し、Textプロパティにテキストを直接セットしています。
TextプロパティはDPとして定義しているのでバインディングの書式も受け入れ可能です。

実行イメージ

感想

ユーザーコントロールとして全く意味のないサンプルコードですが、外側に公開するプロパティ(DP)を決めて上げれば後は、コードビハインドですから、WinFormsみたいにイベントドリブンのコードを書くことに成ります。また、ICommandをバインドすることも出来ます。

以下の記事参照
WPF学習中「ユーザーコントロール」
ユーザーコントロールのサンプルです。Viewに配置するコントロールのソースを分割し再利用することができるようです。プロジェクトの作成PowerShellで実行。要dotnet.exedotnet new wpf -n SimpleUserC...

ただ、こちらはユーザーコントロールのXAMLが定義してあり、レイアウトは直観的でよいのですが、バインドの関係がややこしくなるので、今回のサンプルコードはC#オンリーで作成してみました。

コメント