WPFはやっぱりMVVMでつくりたいですが、最初のプロジェクトをつくるところがちょっと面倒です。
本当はプロジェクトテンプレート的なものにすればいいと思うんですが、とりあえずいつもの手順を書き出してみます。
プロジェクトをつくる
- Visual Studio 2019 を起動し、新しいアプリケーションの作成→WPFアプリケーション(C#) を選択します。
- 適当に情報を入力してプロジェクトをつくります。今回は WPFTestApp という名前にしています。
- プロジェクトができたら、MVVMフレームワークとして、NuGet で ReactiveProperty をインストールします。
(ReactivePropertyについては こちら)
メイン画面をつくる
- Windows という名前のフォルダをつくります。ここにView, ViewModelを入れることにします。
- 自動でできた MainWindow.xaml は削除して、Windows フォルダの中に新しくウィンドウ(WPF) MainWindow.xaml を追加します。※もちろん別の名前でもよいです
- MainWindow.xaml で、Heidht, Width の指定を
SizeToContent="WidthAndHeight"
に書き換えます。(とりあえず) - ViewModelとしてクラス MainWindowViewModel.cs も追加し、アクセス修飾子を
public
にします。また、使わないけど INotifyPropertyChanged を実装します。(メモリリーク対策)
public class MainWindowViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; }
public MainWindow(MainWindowViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
メイン画面を開く
デフォルトではエントリポイントに相当する App.xaml から MainWindow.xaml を開く指定になっていますが、C#のコードのほうがいろいろ制御しやすいので、そのように変えます。
- App.xaml で、
StartupUri="MainWindow.xaml"
をStartup="Application_Startup"
に書き換えます。 - App.xaml.cs で、Application_Startupのイベントハンドラに、
MainWindow
を開くコードを書きます。
private void Application_Startup(object sender, StartupEventArgs e) { var mainWindowVM = new MainWindowViewModel(); new MainWindow(mainWindowVM).ShowDialog(); }
まとめ
ここまで作業を行うと、以下のような状態になります。
MainWindow.xaml
<Window x:Class="WpfTestApp.Windows.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" SizeToContent="WidthAndHeight"> <Grid> </Grid> </Window>
MainWindow.xaml.cs
using System.Windows; namespace WpfTestApp.Windows { public partial class MainWindow : Window { public MainWindow(MainWindowViewModel viewModel) { InitializeComponent(); DataContext = viewModel; } } }
MainWindowViewModel.cs
namespace WpfTestApp.Windows { public class MainWindowViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; } }
App.xaml
<Application x:Class="WpfTestApp.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Startup="Application_Startup"> </Application>
App.xaml.cs
using System.Windows; using WpfTestApp.Windows; namespace WpfTestApp { public partial class App : Application { private void Application_Startup(object sender, StartupEventArgs e) { var mainWindowVM = new MainWindowViewModel(); new MainWindow(mainWindowVM).ShowDialog(); } } }
バインディングを確認する
MainWindowViewModel から MainWindow にバインディングができることを確認します。
public class MainWindowViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public ReactivePropertySlim<string> Greeting { get; } = new ReactivePropertySlim<string>("Hello, world!"); }
<Window x:Class="WpfTestApp.Windows.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" SizeToContent="WidthAndHeight"> <Grid> <TextBlock Text="{Binding Greeting.Value}" FontSize="100" /> </Grid> </Window>
世界に挨拶できました。
修正履歴:
- 2021/11/13 ViewModel の INotifyPropertyChanged 実装を追加(メモリリーク対策)