WPFについて
- WPFってなに?
- WPF(Windows Presentation Foundation)は、Microsoft社が開発したGUI(グラフィカルユーザーインターフェース)開発用のフレームワークです。
- WPFの特長は?
- WPFでは、GUIのデザインを決まったパーツではなく、XAMLと呼ばれる拡張マークアップ言語を使って、いわゆるXMLのように”<>”でタグを記述して画面をデザインしていきます。
かつて、.NET Frameworkのアプリを開発するときに主流だったのはWindows Formsでした。しかし、デザインパーツは決まったものを使用するため「デザイン性」が課題でした。
その点、WPFは自分好みのデザインのパーツが自作できるなど、非常にカスタマイズ性に優れています。
- WPFを使うメリットってあるの?
- WPFは画面表示をXAML、ビジネスロジックをC#で記述するように構成されているため、画面設計とロジック設計を別々に進めることができます。
このように、WPFというのは『GUIデザインの自由度の向上』と、『アプリケーション開発の並行タスク化』を目指したフレームワークということが言えるのではないかと思います。
WPFはVisual Studio上で動作しますので、以下の記事からダウンロード&インストールしてもらえば利用することができます。
WPFの特長を感じてみる
アプリの仕様
AボタンおよびBボタンをクリックした数が表示されるアプリを作ります。
ボタンは交互に押すことを強制するために片方をクリックすると非アクティブになり、もう一方がアクティブになるようにします。
アプリの画面
アプリの画面はこんな感じです。
Windows.Forms版のソースコード
Windows.Formsでは、コード上で参照するときにわかりやすくするためにパーツのプロパティからNameを設定します。




1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
using System; using System.Windows.Forms; namespace WindowsForms { public partial class Form1 : Form { private uint m_Acount; private uint m_Bcount; public Form1( ) { InitializeComponent( ); m_Acount = 0; m_Bcount = 0; BtnA.Enabled = true; BtnB.Enabled = false; } private void ButtonA_Click( object sender, EventArgs e ) { m_Acount++; Lbl_AClick_Count.Text = m_Acount.ToString( ); BtnA.Enabled = false; BtnB.Enabled = true; } private void ButtonB_Click( object sender, EventArgs e ) { m_Bcount++; Lbl_BClick_Count.Text = m_Bcount.ToString( ); BtnA.Enabled = true; BtnB.Enabled = false; } } } |
WPF版のソースコード
通常、WPFのプロジェクトを新規作成すると「①.xamlファイル」と「②.xaml.csファイル」が生成されます。
WPFはこの①にビューを②にビジネスロジックを記述するように設計されているのですが、今回はMVVMパターンでアプリを作成したので、「①.xamlファイル」のみ使用します。
一方、ビジネスロジックについては、追加したViewModelとModelのうちModelに記述することにしました。
アプリ作成は、MVVMフレームワークのPrismを利用しています。
『MVVM』および『Prism』については、こちらで詳しく解説しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
<Window x:Class="WPFs.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:WPFs" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.DataContext> <local:MainWindowViewModel /> </Window.DataContext> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="10*" /> <ColumnDefinition Width="10*" /> </Grid.ColumnDefinitions> <!--行の定義--> <Grid.RowDefinitions> <RowDefinition Height="10*" /> <RowDefinition Height="10*" /> </Grid.RowDefinitions> <Label Grid.Row="0" Grid.Column="0" Content="{ Binding Acount }" FontSize="50" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" /> <Label Grid.Row="0" Grid.Column="1" Content="{ Binding Bcount }" FontSize="50" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" /> <Button Grid.Row="1" Grid.Column="0" Command="{ Binding Abutton_Command }" IsEnabled="{ Binding Abutton_Is_Enabled }" Content="Aボタン" FontSize="36" Height="100" Width="250" /> <Button Grid.Row="1" Grid.Column="1" Command="{ Binding Bbutton_Command }" IsEnabled="{ Binding Bbutton_Is_Enabled }" Content="Bボタン" FontSize="36" Height="100" Width="250" /> </Grid> </Window> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
using Prism.Commands; using Prism.Mvvm; namespace WPFs { public class MainWindowViewModel : BindableBase { private ABCounter m_ABCounter; public DelegateCommand Abutton_Command { get; } public DelegateCommand Bbutton_Command { get; } public uint Acount { get { return m_ABCounter.Acount; } set { m_ABCounter.Acount = value; } } public uint Bcount { get { return m_ABCounter.Bcount; } set { m_ABCounter.Bcount = value; } } public bool Abutton_Is_Enabled { get { return m_ABCounter.Abutton_Is_Enabled; } set { m_ABCounter.Abutton_Is_Enabled = value; } } public bool Bbutton_Is_Enabled { get { return m_ABCounter.Bbutton_Is_Enabled; } set { m_ABCounter.Bbutton_Is_Enabled = value; } } /// <summary> /// コンストラクタ /// </summary> public MainWindowViewModel( ) { m_ABCounter = new ABCounter( ); m_ABCounter.PropertyChanged += ( sender, e ) => RaisePropertyChanged( e.PropertyName ); Abutton_Command = new DelegateCommand( Abutton_Click ); Bbutton_Command = new DelegateCommand( Bbutton_Click ); } private void Abutton_Click( ) { m_ABCounter.A_Add( ); } private void Bbutton_Click( ) { m_ABCounter.B_Add( ); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
using Prism.Mvvm; namespace WPFs { public class ABCounter : BindableBase { private uint m_Acount = 0; public uint Acount { get { return m_Acount; } set { SetProperty( ref m_Acount, value ); } } private uint m_Bcount = 0; public uint Bcount { get { return m_Bcount; } set { SetProperty( ref m_Bcount, value ); } } private bool m_Abutton_Is_Enabled = true; public bool Abutton_Is_Enabled { get { return m_Abutton_Is_Enabled; } set { SetProperty( ref m_Abutton_Is_Enabled, value ); } } private bool m_Bbutton_Is_Enabled = false; public bool Bbutton_Is_Enabled { get { return m_Bbutton_Is_Enabled; } set { SetProperty( ref m_Bbutton_Is_Enabled, value ); } } public void A_Add( ) { Acount++; Abutton_Is_Enabled = false; Bbutton_Is_Enabled = true; } public void B_Add( ) { Bcount++; Abutton_Is_Enabled = true; Bbutton_Is_Enabled = false; } } } |
これでひとまずWindows.Forms、WPFともに同じ動作のアプリを作成することができました。
ある日、アプリの仕様変更の依頼があり、『Labelコントロールへの表示ではなく、TextBoxへの表示に変更になってしまった』としましょう。
すると、Forms版およびWPF版のそれぞれ以下のような変更が必要になります。
TextBoxに変更するためにNameプロパティを変更します。


さらに、これに合わせてロジックも変更する必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
using System; using System.Windows.Forms; namespace WindowsForms { public partial class Form1 : Form { private uint m_Acount; private uint m_Bcount; public Form1( ) { InitializeComponent( ); m_Acount = 0; m_Bcount = 0; BtnA.Enabled = true; BtnB.Enabled = false; } private void ButtonA_Click( object sender, EventArgs e ) { m_Acount++; Txt_AClick_Count.Text = m_Acount.ToString( ); BtnA.Enabled = false; BtnB.Enabled = true; } private void ButtonB_Click( object sender, EventArgs e ) { m_Bcount++; Txt_BClick_Count.Text = m_Bcount.ToString( ); BtnA.Enabled = true; BtnB.Enabled = false; } } } |
WPF版の方はビュー側のXAMLだけ変更すればOKです。
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<Grid.RowDefinitions> <RowDefinition Height="10*" /> <RowDefinition Height="10*" /> </Grid.RowDefinitions> <TextBox Grid.Row="0" Grid.Column="0" Text="{ Binding Acount }" FontSize="50" VerticalAlignment="Center" HorizontalAlignment="Center" /> <TextBox Grid.Row="0" Grid.Column="1" Text="{ Binding Bcount }" FontSize="50" VerticalAlignment="Center" HorizontalAlignment="Center" /> <Button Grid.Row="1" Grid.Column="0" Command="{ Binding Abutton_Command }" IsEnabled="{ Binding Abutton_Is_Enabled }" Content="Aボタン" |
アプリの画面
画面はそれぞれ以下のようになります。
Windows.Formsで作った方はビュー側とロジック側の両方とも変更しないといけませんでした。
一方、WPFで作った方はビュー側を変えるだけで済みました。
システム開発の現場では、改修や機能追加の際はなるべく触る範囲を小さくするのが鉄則です。
その理由は、コードを触るだけバグを盛り込んでしまうリスクが増えるからです。
その意味で、『そもそもロジック側を触る必要がない』というお墨付きは、開発時の心強い味方になってくれるのです。
その他にもWPFの特長は以下のようなものがあります。
- 画面描画性能が高い
- レスポンシブ対応している
- テキストベースで画面レイアウトを構築するのでGitなどのバージョン管理システムと相性がよい(差分が見やすい)
参考までに、今回の記事のソースコードは以下のGithubに置いています。
WPFに先はあるのか?
よくWPFについて議論されるのが、WPFの将来性についてです。
結論から言うと、『まだまだ生き延びるフレームワークだが、活躍の場は少ない』ではないかと思います。
10年以上前のシステムでは、Windows.Formsが当たり前のように使われてましたが、WPFの登場と同じ時期にWPFの将来性を大きく変えるあるものが登場しました。
スマートフォンです。
スマートフォンの登場により、スマートフォンでも業務システムにアクセスしたいという当然とも言える需要が出てきました。
すると、WindowsだけでなくAndroidやIOSでも動作する、いわゆるクロスプラットフォームのアプリケーションを開発する必要があります。
そのため、近年ではデータの処理や保存をバックエンドとなるサーバーで行い、フロントエンドとなるPC上でWebAPIを介してデータを授受し画面上に表示する(Webアプリケーション)が主流になっており、Windowsでの動作に限定されるWPFにはあまりスポットが当たらないのが現状になっているのです。
しかし、WPFは画面のカスタマイズ性に非常に優れており、いわゆるjavascript系のフロントエンド向け言語よりも柔軟な画面設計が可能です。また、何より開発元があのMicrosoft社なので、そう簡単にWPFを過去のものにするような扱いはしないでしょう。
以上のことから、今からプログラミングを学ぶ人にはあまりおすすめしませんが、より凝ったデザインに仕上げたい場合や他の言語でイメージ通りの画面が作れない場合は一つの選択肢になるんじゃないかなと思います。