IgbGridではIgbColumnのBodyTemplateプロパティを使用してセルにカスタムのコントロールを配置することができます。

ここでは、BodyTemplateにIgbMultiColumnComboBoxを配置し、セルの値を複数列のデータをもつドロップダウンから選択して編集する方法をご紹介します。

<IgbGrid AutoGenerate="false"
         Id="grid"
         Data="GridData"
         PrimaryKey="ID"
         Name="grid"
         @ref="grid">
    <IgbColumn Field="ID"
               Header="ID"
               Name="ID"
               Width="150px"
               Sortable="true">
    </IgbColumn>
    <IgbColumn Name="ContactName"
               Field="ContactName"
               Header="ContactName"
               Width="250px"
               Sortable="true">
    </IgbColumn>
    <IgbColumn Field="Country"
               Header="Country"
               Editable="false"
               Width="450px"
               Sortable="true">
        <BodyTemplate>
            <IgbMultiColumnComboBox @key="context.Cell.Id.RowID"
                                    DataSource="ComboData"
                                    Value="@(context.Cell.Value)"
                                    Width="400px" DefaultColumnWidth=140
                                    TextField="Name"
                                    ValueField="@(new []{ "CountryID" })"
                                    Fields="@(new [] {"Name", "Continent", "Pop"})"
                                    SelectedValueChanged="(args => OnSelectedValueChanged(args, context))">
            </IgbMultiColumnComboBox>
        </BodyTemplate>
    </IgbColumn>
</IgbGrid>

IgbGridのPrimaryKeyプロパティには行を一意に決定づける値をもつ列(ここではID列)を指定しておきます。

Country列のBodyTemplateにIgbMultiColumnComboBoxを配置しています。ここでの実装のポイントは、IgbMultiColumnComboBoxに@keyを設定しておくことです。値は一意となるものなら何でもよいのですが、ここでは値を”context.Cell.Id.RowID”としてIgbGridのPrimaryKeyに設定した列の値をそのまま使用するようにしています。@keyの設定があることにより、各行に配置されたIgbMultiColumnComboBoxをBlazorが個別に判別できるようになり、値の更新や並べ替えなどの操作を正しいインスタンスに対して行うことができるようになります。(ASP.NET Core Razor コンポーネント – 要素またはコンポーネントの保持の制御での @key の使用 https://learn.microsoft.com/ja-jp/aspnet/core/blazor/components/?view=aspnetcore-7.0#use-key-to-control-the-preservation-of-elements-and-components)

DataSourceに割り当てたComboDataは以下のようなデータを使用します。

private List<CountryItem> ComboData = new CountriesData();

public class CountryItem
{
	public string? CountryID { get; set; }
	public string? Name { get; set; }
	public string? Continent { get; set; }
	public int? Pop { get; set; }
}

public class CountriesData : List<CountryItem>
{
	public CountriesData()
	{
		this.Add(new() { CountryID = "c1", Continent = "Africa", Name = "Angola", Pop = 19618432 });
		this.Add(new() { CountryID = "c2", Continent = "Asia", Name = "Bangladesh", Pop = 150493658 });
...
	}
}

Valueプロパティにはセルの値をバインドするため”@(context.Cell.Value)”とし、TextFieldとValueFieldにはそれぞれセルの表示テキストとなる列と値を保持する列を設定します。ここでは、上記CountryItemクラスのNameとCountryIDを指定しています。また、Fieldsプロパティにはドロップダウンに表示する列を配列で設定します。

最後に、SelectedValueChangedイベントを実装し、IgbMultiColumnComboBoxで行われた選択値の変更をIgbGridのセルの値へと同期させる処理を行います。SelectedValueChangedは”(args => OnSelectedValueChanged(args, context))”と記述し、本来のイベント引数(args)に加えてBodyTemplateのコンテキストデータ(context)を送るようにします。c#側ではOnSelectedValueChangedイベントを以下のように実装します。

private IgbGrid? grid;
public readonly CustomersData GridData = new CustomersData();
.....
private void OnSelectedValueChanged(IgbMultiColumnComboBoxValueChangedEventArgs args, IgbCellTemplateContext context)
{
	var dataIndex = GridData.FindIndex(data => data.ID == context.Cell.Id.RowID);

	if (dataIndex == -1) return;

	var targetData = GridData[dataIndex];
	targetData.Country = args.NewValue.ToString();

	grid?.NotifyUpdateItem(GridData, dataIndex, targetData);
}

イベント引数から取得した行ID(context.Cell.Id.RowID)をIgbGridにバインドしたデータソースで検索し、Countryプロパティの値を同じくイベント引数から取得した新しいセル値(args.NewValue)で書き換えます。その後、IgbGridのNotifyUpdateItem()メソッドを実行してデータソースの変更をIgbGridに伝えます。

実装は以上となります。

本記事で使用したコードのサンプルアプリケーションは以下よりダウンロードいただけます。

Tagged:

製品について

Ignite UI for Blazor