WPFのMVVMで電卓づくり(13)
計算結果の総計を集計するボタン「GT」を実装します
「GT」ボタン1回クリックで現時点での総計を表示させます
「GT」ボタン2回クリックで現時点での総計を破棄させます
構想
MainViewにてエラー時無効となる集計ボタン「GT」とGTマーク表示用画面を実装します
MainModelにて集計ボタンに対応した内部データの更新処理を実装します
実装
構想に沿って各MVVMクラスに追記していきます
MainView
集計ボタン「GT」を実装します
<!--総計ボタン--> <Button Grid.Row="1" Grid.Column="5" Content="GT" CommandParameter="GrandTotal"/>
尚、前回までの実装で既にボタンのStyleにて
IsEnabledにエラー時falseとなるプロパティを紐づけしてあります
「GT」ボタンが有効であることを示すGTマーク表示用画面を出力画面の隣に実装します
<Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <!--GT表示--> <TextBlock Text="{Binding Path=GrandTotalText}"/> <!--エラー表示--> <TextBlock Grid.Row="1" Text="{Binding Path=ErrorText}"/> <!--四則演算子表示--> <TextBlock Grid.Row="2" Text="{Binding Path=OperationText}"/> </Grid> <!--出力画面--> <TextBlock Grid.Column="1" Grid.ColumnSpan="5" Text="{Binding Path=DisplayText}" FontSize="80"/>
MainViewModel
GTマーク更新用プロパティを用意します
public string GrandTotalText { get; set; }
MainViewと紐づけしたプロパティがずいぶん増えてきましたので
UpdateView()を作成してひとまとめにします
public MainViewModel() { model = new MainModel(); UpdateView(); this.PushCommand = new DelegateCommand( param => { if (param == null) { return; } var str = param.ToString(); if (model != null) { if (int.TryParse(str, out int num)) { model.SetText(str); } else { model.SetOperation(str); } UpdateView(); } }, param => { return true; }); } public void UpdateView() { if (model == null) { return; } this.DisplayText = model.DisplayText; RaisePropertyChanged(nameof(this.DisplayText)); this.GrandTotalText = model.GrandTotalValue != 0D ? "GT" : string.Empty; RaisePropertyChanged(nameof(this.GrandTotalText)); this.ErrorText = model.ErrorText; RaisePropertyChanged(nameof(this.ErrorText)); this.IsButtonEnable = string.IsNullOrEmpty(this.ErrorText) ? true : false; RaisePropertyChanged(nameof(this.IsButtonEnable)); this.OperationText = model.OperationText; RaisePropertyChanged(nameof(this.OperationText)); }
MainModel
集計用のプロパティを用意します
// 総計値 public double GrandTotalValue { get; private set; } = 0D;
また、「=」クリック時に集計用プロパティへの加算を行う処理を追記します
case OperationKind.Equal: if (this.IsAdditional) { Calculate(this.Operation); this.IsAdditional = false; } else { this.OriginalText = "0"; } if (double.TryParse(this.DisplayText, out double equalValue)) { this.GrandTotalValue += equalValue; } SetOperationText(ope); this.Operation = OperationKind.Equal; break;
「GT」ボタンクリックでMainViewModel.PushCommand経由で
呼び出されるMainModel.SetOperation()にて
switch-case文に「GT」ボタン用の処理を追記します
case OperationKind.GrandTotal: if (this.Operation == OperationKind.GrandTotal) { Reset(OperationKind.Clear); this.OriginalText = this.GrandTotalValue.ToString(); this.DisplayText = this.OriginalText; this.GrandTotalValue = 0D; SetOperationText(ope); this.Operation = OperationKind.None; } else { this.DisplayText = this.GrandTotalValue.ToString(); this.Operation = OperationKind.GrandTotal; } break;
SetOperationText()に「GT」ボタンを2回クリックした際に「GT」表示を消す処理を追記します
case OperationKind.GrandTotal: if (this.Operation == OperationKind.GrandTotal) { this.OperationText = string.Empty; } break;
「GT」ボタン2回クリック後、数字ボタンを押した際に出力画面との整合性がとれるようにします
public void SetText(string str) { if (this.Operation == OperationKind.Equal || this.Operation == OperationKind.GrandTotal) { this.DisplayText = "0"; } else { this.DisplayText = this.IsAdditional ? this.AffectText : this.OriginalText; } if (this.DisplayText.Equals("0")) { if (str.Equals("0") || str.Equals("00")) { return; } if (!str.Equals(".")) { this.DisplayText = string.Empty; } } // すでに小数点が付与されていたら何もしない if (str.Equals(".") && this.DisplayText.Contains(".")) { return; } this.DisplayText += str; if (this.IsAdditional) { this.AffectText = this.DisplayText; } else { this.OriginalText = this.DisplayText; } }
動作確認
起動後「1」「+」「2」「=」「+」「4」「=」「GT」とクリックした際の画面表示
続けて「GT」「+」「5」「=」「GT」とクリックした際の画面表示