GrapeCity.devlog

グレープシティ株式会社のDeveloper Tools〈開発支援ツール〉の、製品のTIPSや発売などに関する最新情報をお届けします。

GrapeCity

Blazor WebAssemblyでJavaScriptスプレッドシートライブラリを使う

ASP.NET Core Blazorでは、.NETのメソッドからJavaScriptの関数を呼び出したり、逆にJavaScriptの関数から.NETのメソッドを呼び出したりする、「JavaScript相互運用」が可能です。

今回の記事では、Blazor WebAssemblyのアプリケーション上で、ExcelライクなJavaScriptスプレッドシートライブラリ「SpreadJS(スプレッドJS)」のラッパーを作成して使用する方法をご紹介します。

Blazorアプリケーションの作成

開発環境

  • Visual Studio 2019(Version 16.7.4)
  • SpreadJS V13.2J(13.2.3)

まずはBlazor WebAssemblyのアプリケーションを作成します。Blazor WebAssemblyについてはこちらの記事もご覧ください。

Visual Studioのプロジェクトテンプレートから[Blazor アプリ]を選択します。

Blazorアプリの選択

プロジェクト名を「SpreadJS-Blazor-App」として進みます。

プロジェクト名の設定

次にホスティングモデルを選択します。今回は[Blazor WebAssembly App]を選択します。

ホスティングモデルの選択

Blazorコンポーネントの作成

Blazor WebAssemblyのプロジェクトを作成したら、次はそこにBlazor用のコンポーネントを追加していきます。

ソリューションを右クリックし、[追加]⇒[新しいプロジェクト]を選択し、[Razor クラス ライブラリ]を追加します。

Razorクラスライブラリの追加

プロジェクト名を「SpreadJS_Blazor_Lib」として進みます。

Razorクラスライブラリのプロジェクト名を設定

プロジェクトが作成されたら、SpreadJSの製品版、またはトライアル版のZipファイルからJSファイルとCSSファイルをwwwroot配下にコピーします。

SpreadJSのファイルをコピー

exampleJsInterop.jsを以下のように修正します。こちらのコードがC#からJavaScriptのコードを実行するためのブリッジの役割を果たします。

window.sjsAdaptor = {
    init: function (host, config) {
        // GC.Spread.Sheets.LicenseKey = "ライセンスキーがある場合は設定します。";
        if (config.hostStyle) {
            var hostStyle = config.hostStyle;
            var styles = hostStyle.split(';');
            styles.forEach((styleStr) => {
                var style = styleStr.split(':');
                host.style[style[0]] = style[1];
            });
            delete config.hostStyle;
        }

        return new GC.Spread.Sheets.Workbook(host, config);
    },

    setCulture: function (locale) {
        GC.Spread.Common.CultureManager.culture(locale);
    }
};

プロジェクトにデフォルトで追加されるComponent1.razorのファイル名をSpreadJS.razorに変更し、以下のコードを記述します。

@using Microsoft.JSInterop
@inject IJSRuntime JSRuntime


<div @ref="host"></div>

@code {
    [Parameter]
    public int SheetCount { get; set; }

    [Parameter]
    public string HostStyle { get; set; }

    private ElementReference host;

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            JSRuntime.InvokeVoidAsync("sjsAdaptor.setCulture", "ja-jp");
            JSRuntime.InvokeVoidAsync("sjsAdaptor.init", host, new Dictionary<string, object>() {
            { "sheetCount", SheetCount},
            { "hostStyle", HostStyle }
        });
        }
    }
}

BlazorアプリケーションからBlazorコンポーネントを呼び出す

次に、作成したBlazorコンポーネントをBlazorアプリケーションから参照して実行します。

「SpreadJS_Blazor_App」プロジェクトを右クリックし、[追加]⇒[プロジェクト参照]をクリックし、「SpreadJS_Blazor_Lib」を追加します。

プロジェクト参照を追加

「SpreadJS_Blazor_App」のPages/Index.razorを以下のように修正します。

@page "/"

@using SpreadJS_Blazor_Lib

<h1>Hello, SpreadJS!</h1>

<SpreadJS SheetCount="3" HostStyle="@HostStyle" />

@code {
    private string HostStyle { get; set; } = "width:90wh;height:70vh;border: 1px solid darkgray";
}

wwwroot/index.htmlを以下のように修正して、SperadJSのスクリプトとCSSファイルへの参照を追加します。

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>BlazorApp1</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />

    <link href="_content/SpreadJS_Blazor_Lib/SpreadJS/css/gc.spread.sheets.excel2013white.13.2.3.css" rel="stylesheet" />
    <script src="_content/SpreadJS_Blazor_Lib/SpreadJS/scripts/gc.spread.sheets.all.13.2.3.min.js" type="text/javascript"></script>
    <script src="_content/SpreadJS_Blazor_Lib/SpreadJS/scripts/resources/ja/gc.spread.sheets.resources.ja.13.2.3.min.js" type="text/javascript"></script>
    <script src="_content/SpreadJS_Blazor_Lib/exampleJsInterop.js" type="text/javascript"></script>
</head>

<body>
    <app>Loading...</app>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>
    <script src="_framework/blazor.webassembly.js"></script>
</body>

</html>

「SpreadJS_Blazor_App」をスタートアッププロジェクトに設定して実行すると、以下のようにBlazorの画面上にSpreadJSが表示できます。

BlazorでSpreadJSを表示

SpreadJSの機能の使用

SpreadJSをBlazorの画面に表示することができたので、次はSpreadJSの各種機能を使用してみます。今回は指定したセルに値を設定する「setValueメソッド」と「Excelファイルのインポート機能」をそれぞれ追加してみます。

「SpreadJS_Blazor_Lib」のexampleJsInterop.jsを以下のように書き換えます。

window.sjsAdaptor = {
    init: function (host, config) {
        //GC.Spread.Sheets.LicenseKey = "ライセンスキーがある場合は設定します。";
        if (config.hostStyle) {
            var hostStyle = config.hostStyle;
            var styles = hostStyle.split(';');
            styles.forEach((styleStr) => {
                var style = styleStr.split(':');
                host.style[style[0]] = style[1];
            });
            delete config.hostStyle;
        }

        return new GC.Spread.Sheets.Workbook(host, config);
    },

    setCulture: function (locale) {
        GC.Spread.Common.CultureManager.culture(locale);
    },

    setValue: function (host, sheetIndex, row, col, value) {
        var spread = GC.Spread.Sheets.findControl(host);
        if (spread) {
            var sheet = spread.getSheet(sheetIndex);
            sheet.setValue(row, col, value);
        }
    },

    openExcel: function (host, inputFile) {
        var spread = GC.Spread.Sheets.findControl(host);
        if (spread) {
            var excelIO = new GC.Spread.Excel.IO();
            excelIO.open(inputFile.files[0], function (json) {
                spread.fromJSON(json);
            })
        }
    }
};

SpreadJS.razorを以下のように書き換えます。

@using Microsoft.JSInterop
@inject IJSRuntime JSRuntime


<div @ref="host"></div>

@code {
    [Parameter]
    public int SheetCount { get; set; }

    [Parameter]
    public string HostStyle { get; set; }

    private ElementReference host;

    public void setValue(int sheetIndex, int row, int col, object value)
    {
        JSRuntime.InvokeVoidAsync("sjsAdaptor.setValue", host, sheetIndex, row, col, value);
    }

    public void OpenExcel(ElementReference inputFile)
    {
        JSRuntime.InvokeVoidAsync("sjsAdaptor.openExcel", host, inputFile);
    }

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            JSRuntime.InvokeVoidAsync("sjsAdaptor.setCulture", "ja-jp");

            JSRuntime.InvokeVoidAsync("sjsAdaptor.init", host, new Dictionary<string, object>() {
            { "sheetCount", SheetCount},
            { "hostStyle", HostStyle }
        });
        }
    }
}

「SpreadJS_Blazor_App」のwwwroot/index.htmlを以下のように書き換えます。

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>BlazorApp1</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />

    <link href="_content/SpreadJS_Blazor_Lib/SpreadJS/css/gc.spread.sheets.excel2013white.13.2.3.css" rel="stylesheet" />
    <script src="_content/SpreadJS_Blazor_Lib/SpreadJS/scripts/gc.spread.sheets.all.13.2.3.min.js" type="text/javascript"></script>
    <script src="_content/SpreadJS_Blazor_Lib/SpreadJS/scripts/resources/ja/gc.spread.sheets.resources.ja.13.2.3.min.js" type="text/javascript"></script>
    <script src="_content/SpreadJS_Blazor_Lib/SpreadJS/scripts/interop/gc.spread.excelio.13.2.3.min.js" type="text/javascript"></script>
    <script src="_content/SpreadJS_Blazor_Lib/SpreadJS/scripts/plugins/gc.spread.sheets.shapes.13.2.3.min.js" type="text/javascript"></script>
    <script src="_content/SpreadJS_Blazor_Lib/SpreadJS/scripts/plugins/gc.spread.sheets.charts.13.2.3.min.js" type="text/javascript"></script>
    <script src="_content/SpreadJS_Blazor_Lib/exampleJsInterop.js" type="text/javascript"></script>
</head>

<body>
    <app>Loading...</app>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>
    <script src="_framework/blazor.webassembly.js"></script>
</body>

</html>

Pages/Index.razorを以下のように修正します。

@page "/"

@using SpreadJS_Blazor_Lib

<h1>Hello, SpreadJS!</h1>
<table>
    <tr>
        <td>
            <label>シート</label>
            <input @bind-value="@SheetIndex" />
        </td>
        <td>
            <label>行</label>
            <input @bind-value="@Row" />
        </td>
        <td>
            <label>列</label>
            <input @bind-value="@Column" />
        </td>
        <td>
            <lable>値</lable>
            <input @bind-value="@Value" />
        </td>
    </tr>
    <tr>
        <td>
            <button @onclick="doSomething">アップデート</button>
        </td>
    </tr>
    <tr>
        <td>
            <input type="file" @ref="inputFileEle" @onchange="ImportExcel" />
        </td>
    </tr>
</table>
<br />
<SpreadJS SheetCount="3" HostStyle="@HostStyle" @ref="ss" />

@code {
    private SpreadJS ss;

    private ElementReference inputFileEle;

    public int SheetIndex { get; set; } = 0;

    public int Row { get; set; } = 0;

    public int Column { get; set; } = 0;

    public string Value { get; set; } = "";

    private string HostStyle { get; set; } = "width:90wh;height:70vh;border: 1px solid darkgray";

    private void doSomething()
    {
        ss.setValue(SheetIndex, Row, Column, Value);
    }

    private void ImportExcel()
    {
        ss.OpenExcel(inputFileEle);
    }
}

実行結果

実行結果は以下の通りです。

setValueを実行

Excelインポートを実行

おわりに

JavaScript相互運用は、ファイルアクセスなどBlazorに足りない機能を補うために欠かせないものです。また、SpreadJSのような高機能なJavaScriptライブラリをそのまま使えるというのも魅力の一つです。

今回作成したサンプルは以下で公開しています。

製品WebサイトではSpreadJSの機能を手軽に試せるデモをご用意していますので、ぜひご覧ください。

  • グレープシティ株式会社のDeveloper Tools〈開発支援ツール〉の製品・技術資料をご覧ください。
  • グレープシティ株式会社のDeveloper Tools〈開発支援ツール〉の製品のデモアプリケーションをお試しください。