びおりんのブログ

きままにアプリのできるまでを公開していきます

WPFのMVVMで電卓づくり(15)

指定した有効桁数で出力画面の数値を表示し
桁あふれを起こしたらエラー表示させる機能を実装します

構想

MainModelにて桁あふれを起こしたらエラー表示させる機能を実装します

実装

構想に沿って各MVVMクラスに追記していきます

MainModel

有効桁数のフィールドを固定値で設定します

       // 有効桁数
        private const int DIGITS = 12;

数字ボタンクリックでMainViewModel.PushCommand経由で
呼び出されるMainModel.SetText()にて現在の桁数が
DIGITSを超える場合、末尾への数字の追加をスルーするように追記します

       public void SetText(string str)
        {
            if (this.Operation == OperationKind.Equal
             || this.Operation == OperationKind.GrandTotal)
            {
                this.DisplayText = "0";
                this.Operation = OperationKind.None; //バグ修正
            }
            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;
            }

            // データの入力桁数が規定より多い場合何もしない
            if (this.DisplayText.Replace("-", "").Length >= DIGITS)
            {
                return;
            }
            this.DisplayText += str;

            if (this.IsAdditional)
            {
                this.AffectText = this.DisplayText;
            }
            else
            {
                this.OriginalText = this.DisplayText;
            }
        }

四則演算子ボタンクリックでMainViewModel.PushCommand経由で
呼び出されるMainModel.Calculate()のswitch-case文にて計算結果の桁数が
DIGITSを超えているかチェックするメソッドCheckDigits()を呼び出します

               // 四則演算
                case OperationKind.Plus:
                    originalValue += affectValue;
                    originalValue = CheckDigits(originalValue);
                    this.OriginalText = originalValue.ToString("G17");
                    this.AffectText = "0";
                    this.DisplayText = this.OriginalText;
                    break;
                case OperationKind.Minus:
                    originalValue -= affectValue;
                    originalValue = CheckDigits(originalValue);
                    this.OriginalText = originalValue.ToString("G17");
                    this.AffectText = "0";
                    this.DisplayText = this.OriginalText;
                    break;
                case OperationKind.Multiply:
                    originalValue *= affectValue;
                    originalValue = CheckDigits(originalValue);
                    this.OriginalText = originalValue.ToString("G17");
                    this.AffectText = "0";
                    this.DisplayText = this.OriginalText;
                    break;
                case OperationKind.Divide:
                    if (affectValue == 0)
                    {
                        originalValue = 0;
                        this.ErrorText = "E";
                    }
                    else
                    {
                        originalValue /= affectValue;
                    }
                    originalValue = CheckDigits(originalValue);
                    this.OriginalText = originalValue.ToString("G17");
                    this.AffectText = "0";
                    this.DisplayText = this.OriginalText;
                    break;
                default:
                    break;

CheckDigits()を作成します

       public double CheckDigits(double doubleValue)
        {
            string sign = doubleValue < 0D ? "-" : string.Empty;
            long longValue = (long)doubleValue;
            var longAbsText = Math.Abs(longValue).ToString();
            var doubleAbsText = Math.Abs(doubleValue).ToString("F" + DIGITS);
            if (longAbsText.Length > DIGITS)
            {
                // オーバーフロー
                this.ErrorText = "E";
                // オーバー桁数
                var overDigits = longAbsText.Length - DIGITS;
                longAbsText = longAbsText.Insert(overDigits, ".");
                // .より左側が有効桁数を超えた部分
                return double.Parse((sign + longAbsText).Substring(0, DIGITS));
            }
            else if (doubleAbsText.Length > DIGITS)
            {
                return double.Parse((sign + doubleAbsText).Substring(0, DIGITS));
            }
            else
            {
                return doubleValue;
            }
        }

CheckDigits()では、有効桁数の範囲での最大値を超えるとエラー表示させます
また、小数点以下の有効桁数を超える微細な値を切り捨てています
※有効桁数は符号を除いて12桁にしています

また、割愛しますがdouble型からstring型に変換して代入している個所を
下記のようなパターンに置き換えることで、「GT」や「%±」呼び出し時等にも
桁あふれによるエラー表示ができるようにしています

                           //this.DisplayText = GrandTotalValue.ToString();
                            var grandTotalValue = CheckDigits(this.GrandTotalValue);
                            this.DisplayText = grandTotalValue.ToString("G17");

リファクタリング不足で少し冗長なのはご愛嬌ということでお願いします

動作確認

「999999999999 x 12345 =」と入力した際の画面表示
f:id:kazoojapan1985:20200508004017p:plain 「0.9999999999 x 0.12345 =」とクリックした際の画面表示
f:id:kazoojapan1985:20200508002143p:plain

余談

今回で一旦電卓としての機能の実装は終わりにしたいと思います

参考にした電卓「HS-1220TSG」には他にも機能がありますが
簿記の試験でも受けない限り使わないものばかりですのでスルーします

次回からは、気が向いたら電卓の入力履歴を自動でログ出力する機能でも
作ってみようと思います