[Blazor]MatBlazor使ってみた

# はじめに

Blazor向けのUIフレームワークであるMatBlazorのコンポーネントをいくつか使ってみたので、その備忘録です。
MatBlazorを使えば簡単に見た目をマテリアルデザインにできます。

## 事前準備

導入は[公式サイト](https://www.matblazor.com/#:~:text=2.9.0%2Ddevelop%2D042-,Installation,-Install%20MatBlazor%20library)のInstallation通りにやれば大丈夫です。
ただ、BlazorのサーバーアプリでMatTableという表のコンポーネントを使用する場合は、[こちらのissue](https://github.com/SamProf/MatBlazor/issues/196)にある通り、HttpClientをDIコンテナに登録する必要があります。
以下のように登録しました。
登録の際は、シングルトンでもトラジエントでもなくスコープで登録する必要があるみたいです。
詳しくは[こちら](https://docs.microsoft.com/ja-jp/aspnet/core/blazor/fundamentals/dependency-injection?view=aspnetcore-6.0#:~:text=HttpClient%20%E3%81%AF%E3%80%81%E3%82%B7%E3%83%B3%E3%82%B0%E3%83%AB%E3%83%88%E3%83%B3%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8F%E3%80%81%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%97%20%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%A8%E3%81%97%E3%81%A6%E7%99%BB%E9%8C%B2%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82%20%E8%A9%B3%E7%B4%B0%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E3%81%AF%E3%80%81%E3%80%8C%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AE%E6%9C%89%E5%8A%B9%E6%9C%9F%E9%96%93%E3%80%8D%E3%82%BB%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E5%8F%82%E7%85%A7%E3%81%97%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%E3%80%82)。

```cs
public class Startup
{
	// This method gets called by the runtime. Use this method to add services to the container.
	// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
	public void ConfigureServices(IServiceCollection services)
	{
		// ...
		services.AddScoped<HttpClient>();
	}
}
```

## MatTextField

テキストボックスのコンポーネントです。
`@bind-Value`で変数とバインドできます。
`type`で入力をテキストや数字などに制限できます。
`Label` ウォーターマークを指定できます。

```cs
<MatTextField type="text" Label="商品名"  @bind-Value="Name" />
<MatTextField type="number" Label="目標割合" @bind-Value="TargetPercentage" />
@code
{
    /// <summary>
    /// 商品名
    /// </summary>
    string Name;

    /// <summary>
    /// 目標割合
    /// </summary>
    int TargetPercentage;
}
```

以下のように表示できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562946/8954ff0f-1082-6533-492c-b61a947a6ba4.png)

入力すると、以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562946/0130a329-4467-366d-8bc3-156004b85d57.png)

## MatSelectItem

ドロップダウンリストのコンポーネントです。
以下はEnumを選択させる例です。
`@bind-Value`に選択した要素とバインドする変数を指定できます。
`Items`に選択肢にしたい配列を設定できます。
`<ItemTemplate>`でどのように選択肢として表示するか指定できます。

```cs
<MatSelectItem @bind-Value="AssetClass" 
                Items="Enum.GetValues(typeof(AssetClass)).Cast<AssetClass>().ToArray()">
                <ItemTemplate Context = "assetClass">
                    <span>@GetSelectDisplayName(assetClass)</span>
                </ItemTemplate>
</MatSelectItem>
@code
{
    /// <summary>
    /// アセットクラス
    /// </summary>  
    AssetClassType AssetClass;

    /// <summary>
    /// ドロップダウンリストの選択肢の名前に表示する用の文字列を返す
    /// </summary>
    /// <param name="assetClass">アセットクラス</param>
    /// <returns></returns>
    private string GetSelectDisplayName(AssetClass assetClass)
    {
        return assetClass switch
        {
            AssetClass.Unset=>"選択しない",
            AssetClass.Cash => "現金",
            AssetClass.Commodities => "コモディティ",
            AssetClass.DevelopedCountryBonds => "先進国債券",
            AssetClass.DevelopedStocks => "先進国株式",
            AssetClass.DomesticBonds => "国内債券",
            AssetClass.DomesticStocks => "国内株式",
            AssetClass.EmergingMarketBonds => "新興国債券",
            AssetClass.EmergingMarketsStocks => "新興国株式",
            _ => ""
        };
    }
}

```

以下のように表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562946/2eba5ea9-0558-9416-6485-0012247b9aae.png)



## MatTable

表のコンポーネントです。
`Items`で表の要素となるコレクションを指定できます。
`ShowPaging`で表にページング機能を付けれます。
`<MatTableHeader>`で列の定義ができます。
列幅調整は[こちら](https://stackoverflow.com/questions/65481145/controlling-width-of-mattable-column)を参考にしています。cssで指定できるかもしれません。
`<MatTableRow>`で行の定義ができます。
`Items`に指定したコレクションの一要素を`context`でアクセスすることができます。
MatBlazorを使わず、HTMLのそのままの表を使用した場合は`@foreach`で要素の数分行を追加する必要がありますが、それは不要です。

以下の例では上記で使ったコンポーネントを組み合わせて表にしています。
シンプルな例は[公式ドキュメント](https://www.matblazor.com/Table)を参照ください。

```cs
<MatTable Items="@m_AssetInfoCollection.AssetInfos" AllowSelection="true" Striped="false" ShowPaging="false" >
    <MatTableHeader>
        <th><div style="width: 200px">商品名</div></th>
        <th><div style="width: 200px">アセットクラス</div></th>
        <th><div style="width: 200px">評価金額</div></th>
        <th><div style="width: 200px">割合(%)</div></th>
        <th><div style="width: 200px">目標割合(%)</div></th>
    </MatTableHeader>
    <MatTableRow>
        <td><MatTextField type="text" @bind-Value="context.Name" /></td>
        <td>
            <MatSelectItem @bind-Value="context.AssetClass" 
                           Items="Enum.GetValues(typeof(AssetClassType)).Cast<AssetClassType>().ToArray()">
                <ItemTemplate Context = "assetClass">
                    <span>@GetSelectDisplayName(assetClass)</span>
                </ItemTemplate>
            </MatSelectItem>
        </td>
        <td><MatTextField type="number" @bind-Value="context.AppraisedValue" /></td>
        <td>@Math.Round(context.ActualPercentage, 1)</td>
        <td><MatTextField type="number" @bind-Value="context.TargetPercentage" /></td>
    </MatTableRow>
</MatTable>

@code
{
    /// <summary>
    /// アセット情報
    /// </summary>
    private AssetInfoCollection m_AssetInfoCollection = new AssetInfoCollection();

    // ...以下略

}
```

参考までに、以下に上記で使用しているクラスを記載します。

```cs
namespace AssetAllocation_Analysis.Models;

/// <summary>
/// Assetの情報の一覧を表すクラス
/// </summary>
public class AssetInfoCollection
{
  	/// <summary>
	/// アセット情報一覧
	/// </summary>
	public IEnumerable<AssetInfo> AssetInfos => m_AssetInfos;

    // ...以下略
}

/// <summary>
/// Assetの情報を表すクラス
/// </summary>
public class AssetInfo
{
    /// <summary>
	/// 商品名
	/// </summary>
	public string Name { get; set; }

	/// <summary>
	/// アセットクラス
	/// </summary>
	public AssetClassType AssetClass { get; set; }

	/// <summary>
	/// 評価額
	/// </summary>
	public int AppraisedValue { get; set; }

	/// <summary>
	/// 目標の割合
	/// </summary>
	public double TargetPercentage { get; set; }

	/// <summary>
	/// 実際の割合
	/// </summary>
	public double ActualPercentage{ get; set; }

    // ...以下略
}
```

以下のように表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562946/c10cea8c-9aee-f36f-b4f6-b46c922a2467.png)

## MatButton

ボタンのコンポーネントです。
`@onclick`でクリック時の操作を指定できます。

```cs
<MatButton @onclick="AddButtonOnClick">追加</MatButton>
<MatButton @onclick="UpdateButtonOnClick">更新</MatButton>
@code
{
    private void UpdateButtonOnClick()
    {
        // 更新ボタンクリック時の処理
        // ...以下略
    }

    private void AddButtonOnClick()
    {
        // 追加ボタンクリック時の処理
        // ...以下略
    }
}
```

以下のように表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562946/52e73cd4-e2d4-1383-0940-1c4be67cdf64.png)


# さいごに

一番有名でコンポーネント数が多いという記事をよく見かけたため使ってみました。
公式ドキュメントが割と充実しているため使いやすいかなと思いました。
MicrosoftのFluentUIというUIフレームワークの[Blazor版](https://docs.microsoft.com/en-us/fluent-ui/web-components/integrations/blazor)があるので、それも気になっています。

例が特殊でしたが、これは私が個人的に作ろうとしているアセットアロケーション(どの資産にどの程度の比率で資金を配分するか)を確認するためのアプリから引っ張ってきたためです。。。笑
こちらも公開したらまた記事にしようと思います。