【C# WPF】WPFを理解したいC#初心者の話【MVVMパターン編その3】

公開日: 2023/12/18

C# WPFについて学んでいく過程を備忘録として残して置きたいと思います。

1. MVVMパターンの開発


前回は、MVVMパターンでのアプリケーションを開発する為のプロジェクトの最小の基本構成を整えていきました。

あくまで最小の規模になりますが、これからも使っていくところになると思うので、現状のプロジェクトを今後のひな型として保存しておくのも手です。


今回は電卓アプリケーションを実際に作っていきたいと思います。

2. まずはコントロールを配置

まずはユーザーが触るGUIを作ります。

そのためにコントロール一覧からコントロールを作成していきましょう。


その前に、必要な部品を洗い出してみましょう。


前回までの計画ではユーザーに数字を入力してもらうためのテキスト入力エリアを用意する、という方法を考えていましたが、よくよく考えてみると今回の電卓アプリケーションで文字入力の機能は必要なかったですね。

ですので、0~9の数字入力用ボタンで対応してみたいと思います。

パソコンのキーボードにあるテンキーや、実際の電卓と同じようなGUIを用意するイメージです。

それでは必要なGUIを洗い出しましょう。


  ・数字入力用のボタン

  ・それぞれの四則演算に対応したボタン

  ・数値を表示するテキスト表示エリア

  ・テキスト表示エリアの数値をクリアするボタン


今回のアプリケーションに必須のGUIはこれらです。

これをコントロールを配置することで実現していきましょう。


テキスト表示エリアは「TextBox」、その他のGUIは「Button」のコントロールを使用してみます。

アプリケーションのデザインについては学んでいないのでそれっぽい配置をしますが、自分なりに扱いやすい配置を考えてみてください。文字サイズなどもアレンジしてみてください。

私はこのように配置してみました。

3. 変数のバインディング

次は数値表示用のTextBoxの設定を行います。

ここでバインディングというものが登場します。


バインディングとは、画面側でコントロールの値に対して行われた変更を内部側に通知して反映させるような仕組みです。

View側でコントロールの数値が変更された場合、それをViewModelに反映します。

逆にViewModel側でコントロールの数値の変更が行われた場合にその変更の通知をView側に送り、Viewのコントロールの値に変更を反映します。


画面処理と内部処理を切り分けて開発を進めるMVVMパターン特有の動作で、バインディングを行うことで画面側と内部処理側のそれぞれに変更が発生しても大きな影響を与えずに開発を進めることができます。


早速、バインディングをしてみます。まずMainViewModel.csを開き、MainViewModelクラスの中に以下のコードを追加します。

public int TextArea { get; set; } = 0;


これでTextAreaという名前の設定プロパティをViewModelに作成できます。

これを通してTextBoxの値を変更します。初期値は電卓ですので、0にしておきます。


次に、MainWindow.xaml.csを開きます。

まずはMainViewModel.csの名前空間を使用するための以下のusingをソースファイルの頭のほうに記述します。

using CalcApp.ViewModels;


その後、データのやり取りを行うためのDataContextというプロパティを設定していきます。

MainWindowクラスの初期化処理を行うコンストラクタの中身を以下のように変更します。

public MainWindow()
        {
            InitializeComponent();

            DataContext = new MainViewModel();
        }


これでViewとViewModelで双方向のデータのやり取りを行えるようになります。

次は、TextBoxのコントロールについての変更をしていきます。

MainWindow.xamlでTextBoxのまーっくアップを探してください。

見つけたらコード内のTextのマークアップを以下のように変更します。

★Text="{Binding TextArea}"

これでTextBoxの値をTextAreaのプロパティを通じて変更・反映できるようになります。

ここまで来たら一度ビルドしてみて、問題がなければデバッグ起動を行ってみてください。

TextBoxの値が「0」になっていれば成功です。

4. 数字ボタンの実装を考える

今度は数字を入力できるようにしたいですね。どのように実装するべきかを検討してみましょう。

まずは桁数の制限を考えず、基本的なロジックを考えていきます。


電卓では、後に押された数字がより低い桁数になります。(小数点は今回は考えません。)

例えば、最初に「1」のボタンを押すと画面には「1」と表示されます。

そのあとに「2」のボタンを押すと、画面には「12」と表示されます。

単純にテキストとしてこれを表示するだけなら、テキストの末尾に数値を入力していく方式となりますね。


ここから考えられる実装方法としては、一旦はテキスト形式の変数として保持を行い、数字ボタンが入力されるたびにテキスト末尾に入力された数字を追加していき、四則演算のボタンが押された段階でテキストの型を文字型から整数型にキャストする方式です。


文字型を経由しない方式だと、数字ボタンが押されるたびに保持している変数を10倍し、そこに入力された数値を足しこんでいく方式もあります。

入力される桁数は必ずひとケタですので、これでも問題はなさそうですね。


入力データを文字型にしたり整数型にしたりするのは出来れば最小限に抑えたいので、今回は後者の保持している数値データを10倍して入力された数値を足しこむ方式を採用してみようと思います。

ボタンが押された際の処理も考えていきます。

一番単純なのは、ボタンごとに異なる処理を作成しておくことです。

「1」のボタンなら1を足す、「5」のボタンなら5を足す、といった処理をボタン別に作って実装する、少し強引な力技です。


しかしこれでは計算の方式を前者に変えたほうがいい、となってしまった場合に数字ボタンの数だけ処理を作り直さなければなりませんし、何より10つの処理で異なる部分は足しこむ数値だけ、というのは効率が悪く感じます。


ボタンのプロパティから数字を取得するような方法があれば、それをうまく使いたいところです。

5. まとめ

今回は電卓系のアプリケーションをMVVMパターンで開発していきました。

といってもまだ起動したときに0が表示されている程度で、どのボタンを押してもなにも変化がありません。

次回はボタンの実装を進めて実際に計算ができるようになるところまで作ることができれば、と思っています。


次回は関数のバインディングを使うことになり、難易度が上がってきます。

私も学習しながらの備忘録ですので拙いところもあるとは思いますが、何かの参考になればと思います。