プログラミングを試してみたい人向けのC#プログラミングチュートリアル

WPFアプリの作り方

POINT
  • WPFアプリでは、画面デザインはxamlファイルに記載する
  • xamlファイルでの画面デザインはWindowsフォームアプリよりしやすい
  • cscでのコンパイル時に/t:winexeを指定、WPFに必要はdllも指定する
  • cscではxamlファイルを実行時に読み込む必要がある
目次

WPFアプリとは

WPFアプリとは、Windows Presentation Foundationを略した名称です。
読み方は「ダブリューピーエフ」です。
Windowsフォームアプリと同じく画面を使ったプログラムを作れます。
Windowsフォームアプリとの違いを細かく書くと長くなるため、大きな特徴のみ紹介します。
大きな特徴は、画面のデザインをxamlという形式で記載することです。
xamlは、画面構造を階層的に記載することができます。 画面と処理との分割もできるためわかりやすくなっています。
ただし、比較的新しい技術のため、情報が少ないことがデメリットとして挙げられます。

このホームページではWindows標準の環境だけで本格的なプログラムを作成する方法を紹介しています。
IDE(プログラム開発専用のソフト)を使わない場合、画面の配置が面倒という大きなデメリットがあります。
xamlファイルでの画面デザインができるWPFアプリは、IDEを使わないプログラム作成と相性が良いです。

WPFアプリでボタンクリックでのHelloWorldを表示

早速サンプルを紹介していきます。
ボタン一つだけでの簡単はプログラムです。
ボタンをクリックすることで「Hello World!」とメッセージボックスを表示します。

実行結果サンプル

プログラムを実行すると次の画面を表示します。

プログラム実行時の画面

「Click!」のボタンをクリックすると、メッセージボックスを表示します。

HelloWorldのメッセージを表示

プログラム作成

プログラムファイルはメインのProgram.csと画面処理を行うMainWindow.csの2つです。
さらに画面デザインを記載するMainWindow.xamlを1つ作成します。
次のファイルを同じフォルダに作成してください。

Program.cs
using System;
using System.Windows;

namespace SampleProgram 
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            var app = new Application();
            app.Run(new MainWindow().getWindow());
        }
    }
}
MainWindow.cs
namespace SampleProgram 
{
    public class MainWindow
    {
        private System.Windows.Window _window;
        private System.Windows.Controls.Button _button1;

        // コンストラクタ
        public MainWindow()
        {
            // XAMLファイルを読み込んでフォーム生成
            using (var fs = new System.IO.FileStream("MainWindow.xaml", 
                System.IO.FileMode.Open, System.IO.FileAccess.Read))
            {
                _window = (System.Windows.Window)System.Windows.Markup.XamlReader.Load(fs);
            }
            
            // オブジェクト取得
            _button1 = (System.Windows.Controls.Button)_window.FindName("button1");
            
            // イベント設定
            _button1.Click += new System.Windows.RoutedEventHandler(button1_Click);
        }
        
        // Windowクラスを返す
        public System.Windows.Window getWindow()
        {
            return _window;
        }

        // ボタンクリック時の処理
        private void button1_Click(object sender, System.EventArgs e)
        {
            System.Windows.Forms.MessageBox.Show("Hello World!");
        }

    }
}

次がWPFアプリ特有のxamlファイルです。
XMLという<>括りのタグで記載する方式です。
XMLは、<タグ名>でスタートして</タグ名>で終わるまでをグループとして記載することができる方法です。
一つのタグだけで完結する場合は、<タグ名/>のようにタグ名の後ろに/を付けます。

MainWindow.xaml
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="SampleProgram" 
    Width="500"
    Height="300"
    WindowStartupLocation="CenterScreen"
    FontSize="13"
    FontFamily="メイリオ">

    <Button 
        Content="Click!" 
        x:Name="button1" 
        Width="100"
        Height="30"
        Margin="5,5,5,5" />

</Window>

コンパイル用のバッチは次のようになります。

Compile.bat
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe ^
  /t:winexe ^
  /r:"WPF\PresentationCore.dll" ^
  /r:"WPF\PresentationFramework.dll" ^
  /r:"WPF\WindowsBase.dll" ^
  /r:"System.Xaml.dll" ^
  /out:SampleProgram.exe ^
  *.cs
pause

ファイルを作成できたらCompile.batを実行してみましょう。
同じフォルダに/out:で指定しているSampleProgram.exeが作成されます。
SampleProgram.exeを実行して実行結果サンプルの画面が表示されたら成功です。

プログラム解説

作成したプログラムを解説していきます。

cscのオプション指定

WPFアプリを作成する場合、コンパイルする際にdll参照のオプションを追加します。
ファイル「Compile.bat」を参照してください。

Compile.bat
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe ^
  /t:winexe ^
  /r:"WPF\PresentationCore.dll" ^
  /r:"WPF\PresentationFramework.dll" ^
  /r:"WPF\WindowsBase.dll" ^
  /r:"System.Xaml.dll" ^
  /out:SampleProgram.exe ^
  *.cs
pause

まず、Windowsフォームアプリと同様に/t:winexeのオプションを付けます。

3~6行目の/r:で指定しているのがWPFの場合に必要なオプションです。
これがないとWPFアプリで使用するSystem.Windows.Windowクラス等が使えません。
コンパイル時にアセンブリ参照が不足しているというエラーになります。

7行目はWPFアプリとは関係ない、コンソールアプリやWindowsフォームアプリでも使えるオプションです。
作成するexeファイルの名前を指定することができます。

メイン処理の内容

次にファイル「Program.cs」のメイン処理の内容を見ていきます。
Windowsフォームアプリとの違いを説明します。
Windowsフォームアプリについては、Windowsフォームアプリの作り方を参照してください。 冒頭のusingディレクティブから見ていきます。

Program.cs(抜粋)
using System;
using System.Windows;

WPFアプリでは、using System.Windows;を使用します。
Windowsフォームアプリでは、using System.Windows.Forms;としていた部分です。

Program.cs(抜粋)
            var app = new Application();

Windowsフォームアプリでは、newせずに直接ApplicationのRunを呼び出していました。
System.Windows.Forms.Applicationの場合は、newを必要としないstatic形式のクラスだったからになります。
WPFアプリでは、staticではないSystem.Windows.Applicationを使用します。
そのため、まずはnewします。
varは「=の後ろの型に合わせます」という意味になります。
IDE(プログラム開発専用のソフト)を使わない場合、何の型かわかりにくくなるため、当サイトではあまり使っていません。
今回の場合、newするだけではっきりと型を明示しているためvarを使用しました。

Program.cs(抜粋)
            app.Run(new MainWindow().getWindow());

Windowsフォームアプリでは、System.Windows.Forms.Formクラスを渡してRunを呼び出しました。
WPFアプリの場合は、System.Windows.Windowクラスを渡します。
MainWindowクラスのgetWindowメソッドを呼び出して、Windowクラスを取得するようにしています。
cscでのコンパイル制限の都合上、このサンプルではこのような仕組みにしました。
詳細は続いて解説するWindowクラス作成用クラスを参照してください。

Windowクラス作成用クラス

次はファイル「MainWindow.cs」の内容を見ていきます。

MainWindow.cs(抜粋)
        private System.Windows.Window _window;
        private System.Windows.Controls.Button _button1;

Windowsフォームアプリでは、基本的にSystem.Windows.Formsのコントロールを使用しました。
WPFアプリの場合は、System.Windows.Controlsのコントロールを使用します。
なお、クラス内で共有する変数の頭には_を付けるようにしています。
クラス内変数であることがわかりやすいように、使用する際にthis.を付ける方法がありますが、これだとthis.を書き忘れる場合があります。
名前を付ける段階でルールを設けておくことで、統一化しやすくなるメリットがあります。

コンストラクタでは、XAMLファイルを読み込んでフォーム生成します。 WPFではXAMLファイルに画面デザインを記載します。
Visual StudioなどのIDE(プログラム開発専用のソフト)を使用すれば、Windowsフォームアプリと同様にコンパイル時にexeに画面を含めることができます。
それに対しcsc.exeでは、XAMLファイルまでコンパイルができません(少なくとも当ホームページ製作者にはその方法が見つけられませんでした)。
そのため、このサンプルでは画面用クラスの生成時にXAMLファイルを読み込んで、Windowクラスを生成するようにしました。

MainWindow.cs(抜粋)
            // XAMLファイルを読み込んでフォーム生成
            string path = System.AppDomain.CurrentDomain.BaseDirectory;
            using (var fs = new System.IO.FileStream(path+"MainWindow.xaml", 
                System.IO.FileMode.Open, System.IO.FileAccess.Read))
            {
                _window = (System.Windows.Window)System.Windows.Markup.XamlReader.Load(fs);
            }

System.AppDomain.CurrentDomain.BaseDirectoryで、exeファイルがあるパスを取得します。
次の行でFileStreamを使用して、exeファイルと同じフォルダにあるMainWindow.xamlを読み込んでいます。
using句については、ファイル操作を参照してください。
(System.Windows.Window)System.Windows.Markup.XamlReader.Load(fs)で、FileStreamから読み込んだ内容でWindowクラスを生成します。

次のプログラムで、ボタンクリック時のイベント設定を行います。
イベントについては、イベント処理を参照してください。

MainWindow.cs(抜粋)
            // オブジェクト取得
            _button1 = (System.Windows.Controls.Button)_window.FindName("button1");
            
            // イベント設定
            _button1.Click += new System.Windows.RoutedEventHandler(button1_Click);

FindNameでWPF画面のコントロールを取得します。
FindNameはobject型として返ってくるため、頭に(System.Windows.Controls.Button)を付けて型変換しています。

Windowsフォームアプリでは、System.EventHandlerを使ってイベント設定しましたが、WPFではSystem.Windows.RoutedEventHandlerを使用します。

xamlファイルの作り方

xamlファイルは、Windowタグで括って記載します。

MainWindow.xaml
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    ・・・>
    ・・・
</Window>

タグの属性として、各コントロールごとのプロパティを指定します。
下記は画面のプロパティです。

MainWindow.xaml
<Window ・・・
    Title="SampleProgram" 
    Width="500"
    Height="300"
    WindowStartupLocation="CenterScreen"
    FontSize="13"
    FontFamily="メイリオ">

Titleで画面タイトル、WidthとHeightは幅と高さ、WindowStartupLocationは表示位置を表しています。
FontSizeとFontFamilyでフォントサイズとフォント名を指定しています。

Windowタグの中にButtonタグを記載することで、画面上にボタンを配置します。
Marginはコントールの周囲にどのくらいのスペースを設けるかを表します。

MainWindow.xaml

    <Button 
        Content="Click!" 
        x:Name="button1" 
        Width="100"
        Height="30"
        Margin="5,5,5,5" />

これだけ見ても、Windowsフォームアプリのプログラミングよりシンプルであることがわかります。
WPFは、画面サイズに合わせてレイアウトが動的に変わるフレキシブルレイアウトに強いというメリットがあります。
Windowsフォームアプリでもフレキシブルレイアウトは使えますが、残念ながらバグがあり、綺麗に表示しきれません。
相対的なコントロール配置がしやすいWPFは、 IDE(プログラム開発専用のソフト)を使わないプログラミングをする場合、とても適しています。