背景

Ignite UI for Blazor が提供するグリッドコンポーネント、IgbGrid コンポーネントを使ったプログラムにおいて、セル内の描画内容をカスタマイズするために、BodyTemplateInlineEditorTemplate パラメーターにカスタムの描画処理 (セルテンプレート) を実装することがあります。

<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;
  }
  ...

実際に動作する完全な形のサンプルプログラムは、以下のリンク先から参照いただけます。

Tagged:

製品について

Ignite UI for Blazor