IgbGrid には行や列を選択してコピーする機能は ClipboardOptions により標準で用意されていますが、Excel などからコピーしたデータをグリッドへ貼り付ける機能は標準では実装されていません。本記事では、ブラウザ標準の paste イベントを利用してクリップボードのデータを取得し、updateRow() メソッドで既存の行に反映するカスタム JavaScript を実装することで、Excelからのデータ貼り付けに対応する方法を紹介します。
IgbGrid の設定
まず、貼り付け先となる IgbGrid に Id と PrimaryKey を設定します。これらは後述のカスタム JavaScript から、対象のグリッド要素を特定し、行を一意に識別するために使用します。
<IgbGrid AutoGenerate="false"
Id="@GridId"
Data="GridData"
PrimaryKey="ID"
ClipboardOptions="clipboardOptions">
<IgbColumn Field="LastName" Header="姓" ...></IgbColumn>
<IgbColumn Field="FirstName" Header="名" ...></IgbColumn>
<IgbColumn Field="Country" Header="国" ...></IgbColumn>
</IgbGrid>
次に、コンポーネントの初回レンダー後に貼り付け処理を実装した JavaScript モジュールを読み込み、.NET 側の参照を渡してグリッドの初期化を行います。
private const string GridId = "myGrid1";
private DotNetObjectReference<Component>? dotNetHelper;
private IJSObjectReference? _jsModule;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
_jsModule = await JSRuntime.InvokeAsync<IJSObjectReference>(
"import", "./Components/Component.razor.js");
dotNetHelper = DotNetObjectReference.Create(this);
await _jsModule.InvokeVoidAsync("setDotNetHelper", GridId, dotNetHelper);
await _jsModule.InvokeVoidAsync("initGrid", GridId);
}
}
貼り付け処理の実装
IgbGrid はセルにフォーカスがある状態での Ctrl+V を自動で解釈してくれないため、Ctrl+V(または Shift+Insert)を検知したタイミングで、画面外に隠した textarea へフォーカスを移し、その要素で発生する標準の paste イベントを利用してクリップボードの生データを取得します。
const getTextArea = (gridId) => {
const instance = getInstance(gridId);
if (!instance.textArea) {
const txtArea = document.createElement("textarea");
...
txtArea.addEventListener("paste", (eventArgs) => { onPaste(eventArgs, gridId); });
instance.textArea = txtArea;
}
return instance.textArea;
};
const onWebGridPasteFromExcelKeyDown = (eventArgs, gridId) => {
const ctrl = eventArgs.ctrlKey;
const key = eventArgs.keyCode;
if ((ctrl || eventArgs.metaKey) && key === 86 || eventArgs.shiftKey && key === 45) {
getTextArea(gridId).focus();
}
};
隠し textarea で paste イベントが発生したら、clipboardData.getData() でテキストを取得します。Excel からコピーしたデータは行が改行(\n)、列がタブ(\t)で区切られたテキストになるため、この形式に合わせて2次元配列へ分解します。
const onPaste = (eventArgs, gridId) => {
eventArgs.preventDefault();
const data = eventArgs.clipboardData.getData("text/plain");
const processedData = processData(data);
updateRecords(processedData, gridId);
};
const processData = (data) => {
const pasteData = data.split("\n").map(row => row.split("\t"));
const lastRow = pasteData[pasteData.length - 1];
if (lastRow.length === 1 && lastRow[0] === "") {
pasteData.pop();
}
pasteData.forEach(row => {
const lastIndex = row.length - 1;
if (typeof row[lastIndex] === 'string') {
row[lastIndex] = row[lastIndex].replace(/\r$/, '');
}
});
return pasteData;
};
整形した2次元配列は、貼り付け実行時に選択されていたセル(grid.selectedCells[0])を起点として、既存の行・列にのみ反映します。選択セルより左側の列は元の値を保持し、右側の列だけを貼り付けたデータで置き換え、updateRow() メソッドでグリッドを更新したうえで、更新結果を invokeMethodAsync() により .NET 側へ渡します。
const updateRecords = (processedData, gridId) => {
const grid = document.querySelector("#" + gridId);
const cell = grid.selectedCells[0];
const pk = grid.primaryKey;
if (!cell) { return; }
const rowIndex = cell.row.index;
const columns = grid.visibleColumns;
const cellIndex = grid.visibleColumns.indexOf(cell.column);
let index = 0;
const updatedRecs = [];
for (const curentDataRow of processedData) {
const dataRec = grid.data[rowIndex + index];
if (!dataRec) { continue; }
const rowData = {};
const rowPkValue = dataRec[pk];
rowData[pk] = rowPkValue;
for (let j = 0; j < columns.length; j++) {
let currentCell;
if (j >= cellIndex) {
currentCell = curentDataRow.shift();
}
const colKey = columns[j].field;
rowData[colKey] = currentCell ?? dataRec[colKey];
}
grid.updateRow(rowData, rowPkValue);
updatedRecs.push(rowData);
index++;
}
getInstance(gridId).dotNetHelper?.invokeMethodAsync('SyncData', updatedRecs);
};
JavaScript 側から渡された更新内容は、[JSInvokable] 属性を付けた SyncData() メソッドで受け取り、Blazor 側で保持しているグリッドのデータモデルに反映します。
[JSInvokable]
public Task SyncData(List<RowData> updatedRows)
{
if (GridData == null)
{
return Task.CompletedTask;
}
Dictionary<string, RowData> lookup = GridData
.Where(r => r.ID != null)
.ToDictionary(r => r.ID!);
foreach (RowData updated in updatedRows)
{
if (updated.ID != null && lookup.TryGetValue(updated.ID, out RowData? record))
{
record.FirstName = updated.FirstName?.Replace(oldValue: "\r", newValue: "");
record.LastName = updated.LastName?.Replace(oldValue: "\r", newValue: "");
record.Country = updated.Country?.Replace(oldValue: "\r", newValue: "");
}
}
return Task.CompletedTask;
}
実行結果
グリッド上でセルを選択した状態で Excel のセル範囲をコピーし、Ctrl+V(または Shift+Insert)で貼り付けると、選択したセルを起点にコピーしたデータがグリッドへ反映されます。

Excel のデータをコピーして、

グリッドにペーストすることができます。
