WPFでアプリケーションを作成する場合、
-
XAML … 見た目(View)をXMLで記述
-
コードビハインド … 振る舞い(Behavior)をC#で記述
という役割分担で開発することになります。
XAMLは単なる設定ファイルではなく、ビルド時にC#コードへ変換・コンパイルされ、最終的には通常の.NETオブジェクトとして扱われます。
そのため、コードビハインドからは XAML で定義されたコントロールを、
通常のC#オブジェクトと同じように操作できます。
WPFプロジェクトで生成される基本構造
dotnet new wpf などでプロジェクトを作成すると、次の2つのファイルが生成されます。
MainWindow.xaml
MainWindow.xaml.cs
MainWindow.xaml
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="450"
Width="800">
<Grid>
<Button x:Name="MyButton"
Content="Click"
Width="120"
Height="40"/>
</Grid>
</Window>
MainWindow.xaml.cs(コードビハインド)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MyButton.Click += (s, e) =>
{
MessageBox.Show("Clicked");
};
}
}
この形が、WPFにおける最も基本的なWindow定義です。
partial class が意味するもの
ここで重要なのが、この記述です。
public partial class MainWindow : Window
partial が付いている理由は、
MainWindow クラスは、複数のファイルに分かれて定義されている
からです。
XAMLはビルド時にC#コードへ変換される
ビルド時、XAML は内部的に次のようなコードに変換されます。
public partial class MainWindow
{
internal Button MyButton;
private void InitializeComponent()
{
// XAMLの内容に基づいて
// コントロールが生成・配置される
}
}
つまり実際には、
MainWindow.xaml → 自動生成される partial class
MainWindow.xaml.cs → 開発者が書く partial class
この2つが1つのMainWindowクラスとして合成されるわけです。
x:Name を付けるとフィールドが生成される
XAMLで次のように書くと:
<Button x:Name="MyButton" />
ビルド時に次のフィールドが自動生成されます。
internal Button MyButton;
その結果、コードビハインドから
MyButton.Content = "変更";
MyButton.IsEnabled = false;
MyButton.Content = "変更";
MyButton.IsEnabled = false;
と、普通のオブジェクトとしてアクセスできるようになります。
InitializeComponent() の正体
コードビハインドのコンストラクタには、必ず次の行があります。
InitializeComponent();
これは、
-
XAMLを読み込み
-
コントロールを生成し
-
論理ツリー・ビジュアルツリーを構築し
-
x:Name を持つ要素をフィールドに関連付ける
という処理をすべて行う自動生成メソッドです。
WindowはApplicationツリーの一部として管理される
WPFアプリは、次のようなツリー構造を持っています。
Application
└─ Window
└─ Grid
├─ Button
└─ TextBox
Application.Current をルートとして、
Application.Current.Windows
から、すべてのWindowにアクセス可能です。
つまり技術的には、
-
名前空間
-
クラス名
-
オブジェクト参照
が分かっていれば、アプリ内のどこからでもUIへ到達可能です。
まとめ
基本的に、コードビハイドで書くコードは、
MainWindowクラスのコンストラクタを含む内部メソッドの定義になり、
XAMLで配置したコントロールは、クラスのメンバー変数としてアクセスすることが出来ます。
ViewModelなどの別クラスから参照する経路もありますが、
大概の場合、作法から外れますので、考えないほうが良いでしょう。
大まかな関係整理
・XAMLはコードビハンインドを知っている
・コードビハンインドもXAMLを知っている。(最終的に一つのクラスだから)
・ViewModelはXAMLもコードビハインドもしらない(別クラスだから)
・XAML(コードビハインド)はバインディング機構を介してViewModelを利用する。(直接はしらない)
アプリケーションロジックを別クラスに切り出す場合、ViewModelと同じで、直接コントロールを操作する術がない(すべきでない)ので、コントロールを触るコードはコードビハインドに集約させるべきでしょう。
アプリケーションロジッククラスでは、コントロール以外の遷移情報の管理だけになり、ある程度の規模感でない場合はクラスを切り出す必要が無いかもしれません。

コメント