背景
Ignite UI for Blazor が提供するグリッドコンポーネント、IgbGrid コンポーネントを使ったプログラムにおいて、セル内の描画内容をカスタマイズするために、BodyTemplate や InlineEditorTemplate パラメーターにカスタムの描画処理 (セルテンプレート) を実装することがあります。
<IgbGrid Data="_data" ...>
...
<IgbColumn Filed="@nameof(Person.Name)">
<BodyTemplate>
<!-- ここに任意の HTML レンダリング処理を書ける -->
</BodyTemplate>
</IgbColumn>
...
</IgbGrid>
@code {
private List<Person> _data = ...
このとき、そのセル内に描画されるべき値 (つまり、列を定義する IgcColumn コンポーネントにおける Field パラメーターに指定された名前のプロパティの値) は、テンプレート内で暗黙的に参照できる引数、“context” を介して、context.Cell.Value として参照可能です。
<IgbGrid ...>
...
<IgbColumn Filed="@nameof(Person.Name)">
<BodyTemplate>
<!-- テンプレート内では暗黙の引数 "context" が参照できる -->
<span @key="context.Cell.Id.RowID">
<!--
context.Cell.Value にはこのセルに表示されるべき値が格納されている
(この例だと、IgcColumn の Field に "Name" と指定しているので、Name プロパティの値)
-->
@context.Cell.Value
<span>
</BodyTemplate>
</IgbColumn>
...
</IgbGrid>
しかし要件によっては、そのセルテンプレートに表示すべき値のみならず、その値の由来である元の行データであったり、あるいは、その行データから同行の別の列 (プロパティ) を参照したい場合があります。
このような場合は、以下の手順で参照可能です。
手順
まず IgbGrid コンポーネントの PrimaryKey パラメーターに、そのグリッドコンポーネントにバインドするデータ型のうち、一意に行を特定できるユニーク値を持つプロパティの名前を指定してください。
<IgbGrid PrimaryKey="@nameof(Perosn.Id)" ...
次に、セルテンプレート内ですが、テンプレート内の暗黙引数 context を介して、context.Cell.Id.RowID プロパティを参照すると、そのセルの描画元となっている行データの、IgbGrid の PrimaryKey パラメーターで指定した名前のプロパティ値が取得できます。
<IgbGrid PrimaryKey="@nameof(Perosn.Id)" ...>
<IgbColumn ...>
<BodyTemplate>
<!--
この例では、ここで context.Cell.Id.RowID を参照すると、
このセルにバインドされる行データの、Id プロパティの値が取得できる
-->
</BodyTemplate>
...
続けて context.Parent には、そのセルを抱えているグリッドコンポーネント (IgbGrid) への参照が格納されています。これを介して、IgbGrid の Data パラメーターを参照することで、バインドされている元データ全体にもアクセスできます。
<IgbGrid Data="_data" ...>
...
<IgbColumn Filed="@nameof(Person.Name)">
<BodyTemplate>
@{
// context.Parent に、このセルを持つ IgbGrid への参照がある
var grid = context.Parent as IgbGrid;
// IgbGrid の Data を見れば、バインドされているデータ全体を参照できる
var rows = grid?.Data as List<Person>;
}
</BodyTemplate>
</IgbColumn>
...
</IgbGrid>
@code {
private List<Person> _data = ...
この二者を組み合わせて、バインドされている元データ全体から、PrimaryKey に指定された名前のプロパティ値が、context.Cell.Id.RowID に一致する行を探索することで、セルテンプレート内から行データを取得することができます。
<IgbGrid Data="_data" PrimaryKey="@nameof(Person.Id)" ...>
...
<IgbColumn Filed="@nameof(Person.Name)">
<BodyTemplate>
@{
// context.Parent に、このセルを持つ IgbGrid への参照がある
var grid = context.Parent as IgbGrid;
// IgbGrid の Data を見れば、バインドされているデータ全体を参照できる
var rows = grid?.Data as List<Person>;
// context.Cell.Id.RowID に PrimaryKey に指定された名前の
// プロパティ値がある
var rowId = context.Cell.Id.RowID;
// 以上を元にバインド元データを探索すればこのセルの元データ行を取得できる
var row = rows?.First(r => r.Id == rowId);
}
</BodyTemplate>
</IgbColumn>
...
</IgbGrid>
@code {
private List<Person> _data = ...
ひとたび行データが取得できれば、同じ行データ内の任意のプロパティを参照可能です。
<IgbGrid ...>
...
<IgbColumn Filed="@nameof(Person.Name)">
<BodyTemplate>
@{
var grid = context.Parent as IgbGrid;
var rows = grid?.Data as List<Person>;
var rowId = context.Cell.Id.RowID;
var row = rows?.First(r => r.Id == rowId);
// 行データがわかれば、他のプロパティ (列) の値も参照可能
var iconUrl = row?.Country switch {
Country.India => "./img/in.png",
Country.Japan => "./img/jp.png",
Country.UnitedStates => "./img/us.png",
_ => "./img/no-image.png"
};
}
<span @key="context.Cell.Id.RowId">
<img src="@iconUrl" />
<span>@context.Cell.Value</span>
</span>
</BodyTemplate>
</IgbColumn>
...
</IgbGrid>
@code {
private List<Person> _data = ...
実際の実装においては、上記のようにテンプレート内でインラインで実装するのではなく、コンポーネント内のメソッドに切り出したほうがよいかと思います。
<IgbGrid ...>
...
<IgbColumn Filed="@nameof(Person.Name)">
<BodyTemplate>
<span @key="context.Cell.Id.RowID">
<img src="@GetIconUrl(context)" />
<span>@context.Cell.Value</span>
</span>
</BodyTemplate>
</IgbColumn>
...
</IgbGrid>
@code {
private List<Person> _data = ...
private string GetIconUrl(IgbCellTemplateContext context)
{
var grid = context.Parent as IgbGrid;
var rows = grid?.Data as List<Person>;
var rowId = context.Cell.Id.RowID;
var row = rows?.First(r => r.Id == rowId);
// 行データがわかれば、他のプロパティ (列) の値も参照可能
var iconUrl = row?.Country switch {
Country.India => "./img/in.png",
Country.Japan => "./img/jp.png",
Country.UnitedStates => "./img/us.png",
_ => "./img/no-image.png"
};
return iconUrl;
}
...
実際に動作する完全な形のサンプルプログラムは、以下のリンク先から参照いただけます。