📝

Microsoft.Fast.Components.FluentUIのDataGridで表示しきれない項目を折り返し表示できるようにする

2023/08/26に公開

Fluent UI Blazor

今回取り上げるBlazorのUIコンポーネントはマイクロソフトの公式なFluentUI WebコンポーネントのBlazor版のラッピングです。
FluentUI WebコンポーネントはFASTプロジェクト上でビルドされていてすべてのメジャーなブラウザ上で動作します。

FluentDataGrid

FluentUIのGridコンポーネントであるFluentDataGridでのデフォルトの表示では文字数が多くセル内に文字が表示しきれない項目については折り返しなどされず途中で切れてしまいます。

    <FluentDataGrid id="manualGrid" RowsData=@forecasts GridTemplateColumns="1fr 1fr 1fr 2fr" TGridItem=WeatherForecast>
        <PropertyColumn Title="日付・時刻を表示する" Property="@(c => c!.Date)" Sortable="true" Align=Align.Left/>
        <PropertyColumn Title="温度ですよ. (C)" Property="@(c => c!.TemperatureC)" Sortable="true" Align=Align.Center/>
        <PropertyColumn Title="温度ですよ. (F)" Property="@(c => c!.TemperatureF)" Sortable="true" Align=Align.Center/>
        <PropertyColumn Title="お天気の様子ですね!!" Property="@(c => c!.Summary)" Sortable="true" Align=Align.Right/>
    </FluentDataGrid>

Fluent UI Blazorのテンプレート内のFetchData.razorのテンプレートをすこしタイトルを長くして以上のように設定しておきます。
すると実行結果が以下のようになりました。

一部の、タイトルやデータ本文が切れてしまっています。
しかし、しばしば文字を折り返し2行となってもすべての文字を表示したいというそのような要求があることあります。そのような場合どのようにしたらよいか考えてみます。

ソースコードを読もう!

幸いにも当該UIコンポーネントはOSSですのでソースコードが公開されています。ですのでソースコードを読んでどのような作りになっているかを知れば解決できそうです。
もちろん、ドキュメントをみてそこに掲載されている例はまずはその通りにやるのが早いです。

今回は、データ本文についてはドキュメントを見てTemplateColomnでいけそういう目星があったもののタイトル行に関してはプロパティを設定する以外の方法は分からなかったのでソースコードを見てみます。

https://github.com/microsoft/fluentui-blazor/blob/main/src/Microsoft.Fast.Components.FluentUI/Components/DataGrid/Columns/ColumnBase.razor.cs

まず、ColumBase.razor.csを見てみるとHeaderCellItemTemplate がRenderFragmentで定義されてます。これはいけそう。

ほか、ColumBase.csやFluentDataGrid.razor.cs、TemplateColumn.csをみてるとそれぞれのオブジェクト関係が見えてきました。

TemplateColumn
public class TemplateColumn<TGridItem> : ColumnBase<TGridItem>
{
    private static readonly RenderFragment<TGridItem> EmptyChildContent = _ => builder => { };

    /// <summary>
    /// Specifies the content to be rendered for each row in the table.
    /// </summary>
    [Parameter] public RenderFragment<TGridItem> ChildContent { get; set; } = EmptyChildContent;
    
    ....
}
    

https://github.com/microsoft/fluentui-blazor/blob/main/src/Microsoft.Fast.Components.FluentUI/Components/DataGrid/Columns/TemplateColumn.cs
まず、TemplateColumnですがChildContentというのをRanderFragmentで持っています。これはかける。

で、ColumnBaseを継承してますのでこちらを見てみると。。。

ColumnBase
public abstract partial class ColumnBase<TGridItem>
{
    [CascadingParameter] internal InternalGridContext<TGridItem> InternalGridContext { get; set; } = default!;

    /// <summary>
    /// Title text for the column. This is rendered automatically if <see cref="HeaderCellItemTemplate" /> is not used.
    /// </summary>
    [Parameter] public string? Title { get; set; }

    /// <summary>
    /// An optional CSS class name. If specified, this is included in the class attribute of table header and body cells
    /// for this column.
    /// </summary>
    [Parameter] public string? Class { get; set; }

    /// <summary>
    /// If specified, controls the justification of table header and body cells for this column.
    /// </summary>
    [Parameter] public Align Align { get; set; }

    /// <summary>
    /// An optional template for this column's header cell. If not specified, the default header template
    /// includes the <see cref="Title" /> along with any applicable sort indicators and options buttons.
    /// </summary>
    [Parameter] public RenderFragment<ColumnBase<TGridItem>>? HeaderCellItemTemplate { get; set; }
    
    ....
}
    

なるほど、HeaderCellItemTempateっていうのがある。
で、どうもrazorのほうをみてみるとこのオブジェクトがあればこっちが書かれて、なければ既定のものを出力しているっぽい。

https://github.com/microsoft/fluentui-blazor/blob/main/src/Microsoft.Fast.Components.FluentUI/Components/DataGrid/Columns/ColumnBase.razor

結論

FetchData.razor
    <FluentDataGrid RowsData="@forecasts" GridTemplateColumns="1fr 1fr 1fr 2fr" TGridItem=WeatherForecast>
        <TemplateColumn>
            <HeaderCellItemTemplate>
                <div class="title-cell">
                    日付・時刻を表示する
                </div>
            </HeaderCellItemTemplate>
            <ChildContent>
                <div class="cell">
                    @context.Date
                </div>
            </ChildContent>
        </TemplateColumn>
        <TemplateColumn>
            <HeaderCellItemTemplate>
                <div class="title-cell">
                    温度ですよ. (C)
                </div>
            </HeaderCellItemTemplate>
            <ChildContent>
                <div class="cell">
                    @context.TemperatureC
                </div>
            </ChildContent>
        </TemplateColumn>
        <TemplateColumn>
            <HeaderCellItemTemplate>
                <div class="title-cell">
                    温度ですよ. (F)
                </div>
            </HeaderCellItemTemplate>
            <ChildContent>
                <div class="cell">
                    @context.TemperatureF
                </div>
            </ChildContent>
        </TemplateColumn>
        <TemplateColumn>
            <HeaderCellItemTemplate>
                <div class="title-cell">
                    お天気の様子ですね!!
                </div>
            </HeaderCellItemTemplate>
            <ChildContent>
                <div class="cell">
                    @context.Summary
                </div>
            </ChildContent>
        </TemplateColumn>
    </FluentDataGrid>
FetchData.razor.css
.title-cell {
    word-break: break-word;
    white-space: normal;
}

.cell {
    word-break: break-word;
    white-space: normal;
}

先ほどの部分を上記のように書き換えてみた。
すると以下のように折り返しの表示になった。

基本的に、HeaderCellItemTemplateやChildContentの中は自由にHTMLを記述可能ですので工夫によりどのようなデザインでも可能になってきます。

Discussion