WinUI3で超簡易電卓を作る練習(外観編)

:::note info
WinUI3を学びたく、練習として簡単な電卓を作ってみることにしました。
まず最初は外観の部分から成果を記録しておきます。
:::

## 私のレベル
WinUI3だけでなく、C#やxaml自体も入門者のため、効率やセオリーを無視したコーディングをしているかもしれません。

初心者の制作をみてやる、という方はお付き合いください。


## 今回作ろうとしているもの
タイトル通り、超簡易的な電卓アプリです。

外観のデザインがし易く、恐らく内部の計算処理などもそこまで難易度が高くなさそうなので選びました。
実際に電卓などは作ったことはありませんので、ドツボに嵌る可能性はあるでしょうが……。

このアプリでできることは四則演算くらいです。
他のメモリー機能とか、数学的な機能は最初に取り掛かるには大変そうなので取り入れませんでした。

外観は下記画像のような感じになる予定です。

![超簡易電卓外観１１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976537/8a646e98-2b5a-f079-3523-7ba04cd1b785.png)

## 画面のサイズを決める
作成するのは電卓ですので、まず最初に縦長の外観にしようと思ったのですが、xamlにそれっぽいプロパティーが見つかりませんでした。

Windowタグにありそうな感じがしましたが、widthやheightみたいなプロパティーがなく……。
とはいえ、どこに設定すれば良いのか悩んでいました。

結果、ロジック側でならばサイズを変更できましたので、初期処理をしていると思われる個所にリサイズ処理を加えてみました。

ついでにリサイズできないようにもしてみました。

```cs:MainWindow.xaml.cs
namespace Calculator;

public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();

        // ウィンドウのサイズを変更します。
        // SizeInt32(Width, Height)
        SizeInt32 size = new (350, 550);
        AppWindow.Resize(size);

        // ウィンドウをリサイズしないようにします。
        OverlappedPresenter? presenter = AppWindow.Presenter as OverlappedPresenter;
        if (presenter != null)
        {
            presenter.IsResizable = false;
        }
    }
}
```

もっとスマートな方法があるやもしれませんが、取り合えず動きました。

## コントロールの配置
結果と入力の表示領域、数字ボタン、演算子ボタン、クリアボタン、戻るボタン、カッコボタン、小数点ボタンを格子状に配置します。

ここは実装が簡単そうな`Grid`によるレイアウトを採用しました。

### うまくストレッチしません
グリッドにコントロールを埋め込みこと自体は危なげなくできたのですが、各コントロールがグリッドに合わせてストレッチしてくれませんでした。

![超簡易電卓外観２１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976537/c6259838-0d61-d220-7e4f-2bee748db833.png)


<details><summary>xamlコード</summary>

```xml:MainWindow.xaml
<?xml version="1.0" encoding="utf-8"?>
<Window
    x:Class="Calculator.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Calculator"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="超簡易電卓">

    <Grid Width="300" Height="500">
        <!-- 4x7のグリッド -->
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <!-- 結果表示領域 -->
        <TextBox Text="0.0000" FontSize="32"
                     Grid.ColumnSpan="4" Margin="2"
                     TextAlignment="Right" IsReadOnly="True" VerticalAlignment="Bottom" />
        <TextBlock Text="Result" Grid.Row="0" Margin="15" Foreground="Gray" />

        <!-- 入力情報表示領域 -->
        <TextBox Text="0.0000" FontSize="32"
                 Grid.Row="1" Grid.ColumnSpan="3" Margin="2"
                 TextAlignment="Right" IsReadOnly="True" VerticalAlignment="Bottom" />
        <TextBlock Text="Input" Grid.Row="1" Margin="15" Foreground="Gray" />

        <Button Content="C" FontSize="32" Grid.Row="1" Grid.Column="3" Margin="2" />

        <!-- 一段目 -->
        <Button Content="Bs" FontSize="32"  Grid.Row="2" Grid.Column="0" Margin="2" />
        <Button Content="（" FontSize="32" Grid.Row="2" Grid.Column="1" Margin="2" />
        <Button Content="）" FontSize="32" Grid.Row="2" Grid.Column="2" Margin="2" />
        <Button Content="÷" FontSize="32" Margin="2" Grid.Row="2" Grid.Column="3" />

        <!-- 二段目 -->
        <Button Content="７" FontSize="32" Grid.Row="3" Grid.Column="0" Margin="2" />
        <Button Content="８" FontSize="32" Grid.Row="3" Grid.Column="1" Margin="2" />
        <Button Content="９" FontSize="32" Grid.Row="3" Grid.Column="2" Margin="2" />
        <Button Content="×" FontSize="32" Grid.Row="3" Grid.Column="3" Margin="2" />

        <!-- 三段目 -->
        <Button Content="４" FontSize="32" Grid.Row="4" Grid.Column="0" Margin="2" />
        <Button Content="５" FontSize="32" Grid.Row="4" Grid.Column="1" Margin="2" />
        <Button Content="６" FontSize="32" Grid.Row="4" Grid.Column="2" Margin="2" />
        <Button Content="ー" FontSize="32" Grid.Row="4" Grid.Column="3" Margin="2" />

        <!-- 四段目 -->
        <Button Content="１" FontSize="32" Grid.Row="5" Grid.Column="0" Margin="2" />
        <Button Content="２" FontSize="32" Grid.Row="5" Grid.Column="1" Margin="2" />
        <Button Content="３" FontSize="32" Grid.Row="5" Grid.Column="2" Margin="2" />
        <Button Content="＋" FontSize="32" Grid.Row="5" Grid.Column="3" Margin="2" />

        <!-- 五段目 -->
        <Button Content="０" FontSize="32" Grid.Row="6" Grid.ColumnSpan="2" Margin="2" />
        <Button Content="．" FontSize="32" Margin="2" Grid.Row="6" Grid.Column="2" />
        <Button Content="＝" FontSize="32" Margin="2" Grid.Row="6" Grid.Column="3" />
    </Grid>
</Window>
```
</details>

### Viewboxを使用してみました
うまくストレッチするようなプロパティーなどは無いかと探すも見つかりませんでした。
ただ、検索し続けていたら`Viewbox`というものがあり、これを使えばストレッチすることができそうなので早速使ってみました。

`Viewbox`の`Stretch`プロパティーをFillにすることでコントロールがストレッチするようです。
少し手間ですが、早速適用させてみました。

![超簡易電卓外観３.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976537/92dba213-5a74-fb08-1f27-429fa3299ea1.png)

<details><summary>xamlコード</summary>

```xml:MainWindow.xaml
<?xml version="1.0" encoding="utf-8"?>
<Window
    x:Class="Calculator.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Calculator"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="超簡易電卓">

    <Grid Width="300" Height="500">
        <!-- 4x7のグリッド -->
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <!-- 結果表示領域 -->
        <Viewbox Stretch="Fill" Grid.ColumnSpan="4" Margin="2">
            <TextBox Text="0.0000" FontSize="32"
                     TextAlignment="Right" IsReadOnly="True" />
        </Viewbox>
        <TextBlock Text="Result" Grid.Row="0" Margin="10" Foreground="Gray" />

        <!-- 入力情報表示領域 -->
        <Viewbox Stretch="Fill" Grid.Row="1" Grid.ColumnSpan="3" Margin="2">
            <TextBox Text="0.0000" FontSize="32"
                       TextAlignment="Right" IsReadOnly="True" />
        </Viewbox>
        <TextBlock Text="Input" Grid.Row="1" Margin="10" Foreground="Gray" />
        
        <Viewbox Stretch="Fill" Grid.Row="1" Grid.Column="3" Margin="2">
            <Button Content="C" FontSize="32" />
        </Viewbox>

        <!-- 一段目 -->
        <Viewbox Stretch="Fill" Grid.Row="2" Grid.Column="0" Margin="2">
            <Button Content="Bs" FontSize="32" />
        </Viewbox>
        <Viewbox Stretch="Fill" Grid.Row="2" Grid.Column="1" Margin="2">
            <Button Content="（" FontSize="32" />
        </Viewbox>
        <Viewbox Stretch="Fill" Grid.Row="2" Grid.Column="2" Margin="2">
            <Button Content="）" FontSize="32" />
        </Viewbox>
        <Viewbox Stretch="Fill" Grid.Row="2" Grid.Column="3">
            <Button Content="÷" FontSize="32" Margin="2" />
        </Viewbox>

        <!-- 二段目 -->
        <Viewbox Stretch="Fill" Grid.Row="3" Grid.Column="0" Margin="2">
            <Button Content="７" FontSize="32" />
        </Viewbox>
        <Viewbox Stretch="Fill" Grid.Row="3" Grid.Column="1" Margin="2">
            <Button Content="８" FontSize="32" />
        </Viewbox>
        <Viewbox Stretch="Fill" Grid.Row="3" Grid.Column="2" Margin="2">
            <Button Content="９" FontSize="32" />
        </Viewbox>
        <Viewbox Stretch="Fill" Grid.Row="3" Grid.Column="3" Margin="2">
            <Button Content="×" FontSize="32" />
        </Viewbox>

        <!-- 三段目 -->
        <Viewbox Stretch="Fill" Grid.Row="4" Grid.Column="0" Margin="2">
            <Button Content="４" FontSize="32" />
        </Viewbox>
        <Viewbox Stretch="Fill" Grid.Row="4" Grid.Column="1" Margin="2">
            <Button Content="５" FontSize="32" />
        </Viewbox>
        <Viewbox Stretch="Fill" Grid.Row="4" Grid.Column="2" Margin="2">
            <Button Content="６" FontSize="32" />
        </Viewbox>
        <Viewbox Stretch="Fill" Grid.Row="4" Grid.Column="3" Margin="2">
            <Button Content="ー" FontSize="32" />
        </Viewbox>

        <!-- 四段目 -->
        <Viewbox Stretch="Fill" Grid.Row="5" Grid.Column="0" Margin="2">
            <Button Content="１" FontSize="32" />
        </Viewbox>
        <Viewbox Stretch="Fill" Grid.Row="5" Grid.Column="1" Margin="2">
            <Button Content="２" FontSize="32" />
        </Viewbox>
        <Viewbox Stretch="Fill" Grid.Row="5" Grid.Column="2" Margin="2">
            <Button Content="３" FontSize="32" />
        </Viewbox>
        <Viewbox Stretch="Fill" Grid.Row="5" Grid.Column="3" Margin="2">
            <Button Content="＋" FontSize="32" />
        </Viewbox>

        <!-- 五段目 -->
        <Viewbox Stretch="Fill"
                 Grid.Row="6" Grid.ColumnSpan="2" Margin="2">
            <Button Content="０" FontSize="32" />
        </Viewbox>
        <Viewbox Stretch="Fill" Grid.Row="6" Grid.Column="2">
            <Button Content="．" FontSize="32" Margin="2" />
        </Viewbox>
        <Viewbox Stretch="Fill" Grid.Row="6" Grid.Column="3">
            <Button Content="＝" FontSize="32" Margin="2" />
        </Viewbox>
    </Grid>
</Window>
```
</details>

一応ストレッチしましたが、めちゃ引き延ばされました。
まあ、当然といえば当然ですか……。

### 無難にwidth、heightを指定しました
結局今回のアプリでは動的にコントールを引き延ばす事はありませんので、各コントール毎に幅と高さを設定することで上手くレイアウトさせました。

そして出来たものが最初の画像です。

<details><summary>xamlコード</summary>

```xml:MainWindow.xaml
<?xml version="1.0" encoding="utf-8"?>
<Window
    x:Class="Calculator.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Calculator"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="超簡易電卓">

    <Grid Width="300" Height="500">
        <!-- 4x7のグリッド -->
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <!-- 結果表示領域 -->
        <TextBox Text="0.0000" FontSize="32"
                 TextAlignment="End" IsReadOnly="True"
                 Grid.ColumnSpan="4" Margin="1" />
        <TextBlock Text="Result" Foreground="Gray"
                   VerticalAlignment="Bottom"
                   Grid.Row="0" Margin="10" />

        <!-- 入力情報表示領域 -->
        <TextBox Text="0.0000" FontSize="32"
                 TextAlignment="Right" IsReadOnly="True"
                 Grid.Row="1" Grid.ColumnSpan="3" Margin="1" />
        <TextBlock Text="Input" Foreground="Gray"
                   VerticalAlignment="Bottom"
                   Grid.Row="1" Margin="10" />

        <Button Content="C" FontSize="32"
                Width="70" Height="70"
                Grid.Row="1" Grid.Column="3" Margin="1" />

        <!-- 一段目 -->
        <Button Content="Bs" FontSize="32"
                Width="70" Height="70"
                Grid.Row="2" Grid.Column="0" Margin="1" />
        <Button Content="（" FontSize="32"
                Width="70" Height="70"
                Grid.Row="2" Grid.Column="1" Margin="1" />
        <Button Content="）" FontSize="32"
                Width="70" Height="70"
                Grid.Row="2" Grid.Column="2" Margin="1" />
        <Button Content="÷" FontSize="32"
                Width="70" Height="70"
                Grid.Row="2" Grid.Column="3" Margin="1" />

        <!-- 二段目 -->
        <Button Content="７" FontSize="32"
                Width="70" Height="70"
                Grid.Row="3" Grid.Column="0" Margin="1" />
        <Button Content="８" FontSize="32"
                Width="70" Height="70"
                Grid.Row="3" Grid.Column="1" Margin="1" />
        <Button Content="９" FontSize="32"
                Width="70" Height="70"
                Grid.Row="3" Grid.Column="2" Margin="1" />
        <Button Content="×" FontSize="32"
                Width="70" Height="70"
                Grid.Row="3" Grid.Column="3" Margin="1" />

        <!-- 三段目 -->
        <Button Content="４" FontSize="32"
                Width="70" Height="70"
                Grid.Row="4" Grid.Column="0" Margin="1" />
        <Button Content="５" FontSize="32"
                Width="70" Height="70"
                Grid.Row="4" Grid.Column="1" Margin="1" />
        <Button Content="６" FontSize="32"
                Width="70" Height="70"
                Grid.Row="4" Grid.Column="2" Margin="1" />
        <Button Content="ー" FontSize="32"
                Width="70" Height="70"
                Grid.Row="4" Grid.Column="3" Margin="1" />
        
        <!-- 四段目 -->
        <Button Content="１" FontSize="32"
                Width="70" Height="70"
                Grid.Row="5" Grid.Column="0" Margin="1" />
        <Button Content="２" FontSize="32"
                Width="70" Height="70"
                Grid.Row="5" Grid.Column="1" Margin="1" />
        <Button Content="３" FontSize="32"
                Width="70" Height="70"
                Grid.Row="5" Grid.Column="2" Margin="1" />
        <Button Content="＋" FontSize="32"
                Width="70" Height="70"
                Grid.Row="5" Grid.Column="3" Margin="1" />

        <!-- 五段目 -->
        <Button Content="０" FontSize="32"
                Width="145" Height="70"
                Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="2" Margin="1" />
        <Button Content="．" FontSize="32"
                Width="70" Height="70"
                Grid.Row="6" Grid.Column="2" Margin="1" />
        <Button Content="＝" FontSize="32"
                Width="70" Height="70"
                Grid.Row="6" Grid.Column="3" Margin="1" />
    </Grid>
</Window>

```
</details>


## 次の記事

https://qiita.com/nogino_sanebou/items/161d9971c045b1bd204b