数式計算用のカスタマイズした関数
ReoGrid は Excel と同様の数式計算機能を提供しています。数式計算について詳しくは、「数式計算」をご覧ください。数式計算における関数は、現時点では 50 個以上の内蔵関数を利用できます。関数一覧は、「数式計算用関数一覧」をご覧ください。内蔵した関数以外に、カスタマイズした関数も作成できます。この文書ではカスタマイズした関数について説明します。
カスタマイズした関数を作成
カスタマイズした関数を作成するには、静的なクラス FormulaExtension
を利用します。このクラスは以下の命名空間にあります。
unvell.ReoGrid.Formula
例として、関数の入力値をすべて大文字に変換する関数を作成します。
unvell.ReoGrid.Formula.FormulaExtension.CustomFunctions["myUpper"] =
(cell, args) => {
// パラメータ配列の数を確認
if (args.Length == 0)
{
// 数が0の場合、nullを返す
return null;
}
// 一つ目のパラメータを取得して大文字の文字列に変換
return Convert.ToString(args[0]).ToUpper();
};
上記で作成したカスタマイズした関数を利用します。セルB2に=myUpper("hello")
計算式を設定します。
編集が終了した後、セルのデータが関数の入力値の「hello」から「HELLO」に変わりました。
カスタマイズした関数の定義
FormulaExtension
の CustomFunctions
プロパティは以下のように定義されています。
Dictionary<string name, Func<ReoGridCell cell, object[] args, object>> CustomFunctions
このプロパティは、コールバック関数の配列となります。コールバック関数のパラメータは以下の通りです。
cell
計算式が格納されたセルのインスタンスと関数を呼び出す際のパラメータ配列args
計算式が呼び出される際のパラメータ配列object
関数の返却値
最も簡単な関数のサンプル(Lambda関数)
C#
FormulaExtension.CustomFunctions["myFunc"] = (cell, args) => {
return null;
};
VB.NET:
FormulaExtension.CustomFunctions("myFunc") = Function(cell, args)
Return Nothing
End Function
最も簡単な関数のサンプル(Delegate関数)
C#:
static object MyFunc(ReoGridCell cell, params object[] arguments)
{
return null;
}
Delegate 関数を CustomFunctions
に追加する方法は以下の通りです。
FormulaExtension.CustomFunctions["myFunc"] = MyFunc;
VB.NET:
Shared Function MyFunc(cell As ReoGridCell, ParamArray args As Object()) As Object
Return Nothing
End Function
Delegate 関数を CustomFunctions に追加する方法は以下の通りです。
FormulaExtension.CustomFunctions("myFunc") = AddressOf MyFunc
コールバック関数のセルインスタンス
一つ目のパラメータであるセルのインスタンスは、カスタマイズした関数を利用する計算式が格納されたセルのインスタンスです。
worksheet["A1"] = "=myFunc()";
A1セルにmyFunc
関数を利用する計算式があります。この計算式が実行される場合、コールバック関数のcellパラメータがA1セルのインスタンスになります。関数の中で取得するコードは以下の通りです。
static object MyFunc(ReoGridCell cell, params object[] arguments)
{
MessageBox.Show(cell.Position.ToAddress()); // output: A1
return null;
}
コールバック関数の中でワークシートのインスタンスを取得
セルのインスタンスからワークシートのインスタンスとワークブックのインスタンスを取得できます。
FormulaExtension.CustomFunctions["myFunc"] = (cell, args) =>
{
// ワークシートを取得
var worksheet = cell.Worksheet;
// ワークブックを取得
var workbook = worksheet.Workbook;
...
return null;
};
関数の利用範囲を制限
関数を特定のワークブックのみで利用できるように制限したい場合、ワークブックのインスタンスを取得して当該ワークブックであるかを確認します。利用不可なワークブックの場合、nullを返すことで関数の利用を制限できます。
var worksheet = cell.Worksheet;
var workbook = worksheet.Workbook;
if (workbook != validWorkbook)
{
// 有効なワークブックではない
return null;
}
コールバック関数のパラメータ配列
カスタマイズした関数が呼び出される際、計算式にある関数の呼び出し元のパラメータ配列が args
になります。
worksheet["B2"] = "=myFunc(A1, A2:B3, 100)";
B2セルの計算式には、関数myFunc
を呼び出すために三つのパラメータがあります。
FormulaExtension.CustomFunctions["myFunc"] = (cell, args) =>
{
// argsの内容は
// args[0] = CellPosition(A1)
// args[1] = RangePosition(A2:B3)
// args[2] = 定数100
// args配列のサイズを確認
if (args.Length < 2)
{
// パラメータが二つ未満の場合、nullを返す
return null;
}
return 1;
};
値のパラメータを処理
ReoGrid 内部では常に数値のデータを .NET の double 型として取り扱っています。int 型、long 型、float 型などをセルのデータに設定した場合、自動的に double 型に転換されます。数値のみを含む文字列をセルに設定した場合、文字列から数値を抽出してデータとして設定されます。以下は数式計算における利用する型の一覧です。
数値 | double 型 |
---|---|
ブーリアン型 | bool 型 |
文字列 | string 型 |
日付時間 | DateTime 型 |
セル参照 | CellPosition 構造体 |
範囲参照 | RangePosition 構造体 |
任意の型 | object 型 |
定数
計算式にある数値、文字列、ブーリアンは、定数として取り扱います。
worksheet["A1"] = "=myFunc(10)";
関数myFuncに渡される数値10は定数です。定数は double 型です。カスタマイズした関数でこのパラメータを取得する際に、double であるかを確認して利用します。
FormulaExtension.CustomFunctions["myFunc"] = (cell, args) =>
{
if (args.Length < 1 || !(args[0] is double))
{
// 1一つ目のパラメータは数値型であることが必要
return null;
}
...
};
変数
セルや範囲への参照は変数として取り扱います。例えばmyFunc
関数を以下のように定義します。
FormulaExtension.CustomFunctions["myFunc"] = (cell, args) =>
{
double value = (double)args[0];
return value \* 2;
};
myFunc関数を利用します。A1セルの参照を渡します。
sheet["A1"] = (int)10;
sheet["B1"] = "=myFunc(A1)";
A1セルにint型の10が設定されていますが、myFunc
関数でdouble型として直接利用しても問題ありません。また、A1セルへ参照しているため、A1セルの値が変化したらmyFunc
に渡されるパラメータも変化します。
参照型のパラメータを処理
セルの参照
計算式にセル参照があった場合、ReoGrid は自動的にセルの値を取得してカスタマイズした関数に渡します。サンプルは、上述の「変数」の部分をご覧ください。
範囲の参照
範囲の参照がパラメータとしてカスタマイズした関数に渡される場合、RangePosition
構造体がカスタマイズした関数に渡されます。
worksheet["G2:K3"] = new object[] { 1, 2, 5, 7, 8, 10, 12, 15, 16, 19};
worksheet["L2"] = "=CountEvenNumber(G2:K3)";
CountEvenNumber
関数は指定した範囲から偶数の数をカウントします。定義は以下の通りです。
FormulaExtension.CustomFunctions["CountEvenNumber"] = (cell, args) =>
{
if (args.Length < 1 || !(args[0] is RangePosition))
{
// 一つ目のパラメータが範囲の参照ではない場合処理を終了
return null;
}
RangePosition range = (RangePosition)args[0];
int count = 0;
// 範囲にあるすべてのセルを反復
cell.Worksheet.IterateCells(range, (r, c, inCell) => {
double value;
// 数値型の値をセルから取得
if (ReoGridCellUtility.TryGetNumberData(inCell.Data, out value) {
if ((value % 2) == 0) {
// 数値が偶数であれば+1
count++;
}
}
// trueを渡して反復を続ける
return true;
});
return count;
};
セルの反復関数 IterateCells
について詳しくは、「セルの反復」をご覧ください。
名前範囲の参照
セルの名前
名前範囲の参照先がセルの場合、セルへの参照として処理されます。カスタマイズした関数に命名範囲の名前を渡した場合、参照先のセルのデータが渡されます。
// 名前範囲name1を定義
worksheet.DefineNamedRange("name1", "A1");
// name1にデータを設定
sheet["name1"] = 20;
// B1セルにname1を参照する計算式を設定
sheet["B1"] = "=myFunc(name1)";
計算式が実行される場合、myFunc
関数に渡されるパラメータは double 型の20です。
範囲の名前
名前範囲の参照先が範囲の場合、範囲ポジション RangePosition
構造体が渡されます。
// 名前範囲を定義
worksheet.DefineNamedRange("evenRange", "G2:K3");
// 名前範囲のデータを設定
worksheet["evenRange"] = new object[] { 1, 2, 4, 6, 9, 11, 13, 14, 15, 17 };
// eventRange名前を参照する計算式を設定
worksheet["I2"] = "=CountEvenNumber(evenRange)";
// 計算結果を確認
AssertSame(worksheet["I2"], 4);
結果は4です。範囲の参照を渡した場合と同じ結果となります。
計算式におけるカスタマイズした名前解析
ReoGridでは、セルや範囲への参照に名前を付けて定義できます。定義した名前は計算式の中で参照として利用できます。プログラムで任意の値を名前として定義したい場合、カスタマイズした名前プロバイダを利用します。
カスタマイズした名前プロバイダは FormulaExtension
クラスの NameReferenceProvider
プロパティです。このプロパティに .NET の関数を設定すると、計算式に利用された名前参照の解析ができます。
unvell.ReoGrid.Formula.FormulaExtension.NameReferenceProvider =
(cell, name) =>
{
if (name == "myName1")
return 10;
else if (name == "myName2")
return 20;
else
return null;
};
この例では、計算式に myName1
を含んだ箇所を、数値10に差し替えます。myName2
を含んだ箇所を数値20に差し替えます。
NameReferenceProvider
プロパティの定義は以下の通りです。
Func<ReoGridCell cell, string name, object ret> NameReferenceProvider { get; set; }
myName1
名前を参照する計算式は以下の通りです。
「Enter」を押すと結果が10となります。
myName2
を利用する計算式です。
結果が20となります。
カスタマイズした名前解析を利用して数値定数を増やす
様々な分野のアプリケーションには、それぞれ独自の計算用定数があります。カスタマイズした名前解析を利用すれば、簡単に定数を増やすことができます。以下の例では、カスタマイズした定数PI、EとMyConstをサポートしています。
C#:
private object MathConstantProvider(ReoGridCell cell, string name)
{
switch (name)
{
case "PI": return Math.PI;
case "E": return Math.E;
case "MyConst": return 1.23456;
default: return null;
}
}
// カスタマイズした名前解析を適用
FormulaExtension.NameReferenceProvider = MathConstantProvider;
VB.NET:
Shared Function MathConstantProvider(cell As ReoGridCell, name As String) As Object
Select Case (name)
Case "PI"
Return Math.PI
Case "E"
Return Math.E
Case "MyConst"
Return 1.23456
End Select
Return Nothing
End Function
// カスタマイズした名前解析を適用
FormulaExtension.NameReferenceProvider = AddressOf MathConstantProvider
MyConst名前を利用する計算式は以下の通りです。
worksheet("A1") = "=MyConst"
関数とカスタマイズした名前解析を合わせて活用
カスタマイズした関数とカスタマイズした名前解析を合わせて利用できます。
FormulaExtension.NameReferenceProvider = (cell, name) =>
{
switch (name)
{
case "Pi": return Math.PI;
case "E": return Math.E;
default: return null;
}
};
Pi
を利用する計算式は以下の通りです。
worksheet["D3"] = "=Div100(Pi)";
AssertSame(worksheet["D3"], Math.PI / 100);
ReoScript スクリプト言語実行の拡張関数
ReoGrid の拡張機能版はスクリプト言語実行機能をサポートしています。ReoGrid は ReoScript (第三者ライブラリ)を利用してスクリプト言語実行機能を実現しています。スクリプト言語の文法は ECMAScript/JavaScript に準拠しています。スクリプトの利用によってワークブック、ワークシート、セル、セルのスタイル、罫線、書式などの制御ができ、製品の二次開発などに便利です。スクリプト実行機能について詳しくは、「スクリプト言語実行(準備中)」をご覧ください。
ReoScript ライブラリは標準的なスクリプトランタイム関数を提供しています。 ReoGrid はスプレッドシート制御の関数を提供しています。ReoGrid を利用するアプリケーションでは、スクリプトのためのカスタマイズした関数を作成できます。この文書ではスクリプト言語におけるカスタマイズした関数について説明します。
スクリプト言語用のカスタマイズした関数を作成
ワークブックに Srm
というオブジェクトがあります。このオブジェクトはスクリプト言語実行のランタイムマシンです。Srm
オブジェクトに追加した関数はスクリプトのどこでも利用できます。以下の例では sqrt
関数を追加します。
workbook.Srm["sqrt"] = new NativeFunctionObject("sqrt", (ctx, owner, args) =>
{
if (args.Length < 1)
return NaNValue.Value;
else
return Math.Sqrt(ScriptRunningMachine.GetDoubleValue(args[0], 0));
});
sqrt
関数を利用する計算式を設定します。
var worksheet = reoGridControl.CurrentWorksheet;
worksheet["B3"] = "=sqrt(400)";
セルのデータを編集すると計算式が確認できます。
このカスタマイズした関数 sqrt
は計算式だけではなく、スクリプト言語でも呼び出されます。
スクリプト言語を実行してカスタマイズした関数を作成
スクリプト言語ではグローバルオブジェクト script
が利用できます。このオブジェクトのメソッドとして追加した関数は、グローバル関数となり、スクリプト言語や計算式の中で呼び出すことができます。
カスタマイズした関数のメソッドは、ECMAScript/JavaScript 文法の無名関数、ReoScript のラムダ式のいずれかを設定すると作成できます。
reoGridControl.RunScript("script.myfunc = data => '[' + data + ']';");
myfunc
関数は、入力値の左側と右側に括弧を付けます。