カスタム関数

カスタム数式関数の追加

カスタム関数を追加するには、FormulaExtensionクラスを使用します。以下の例では、指定された文字列を大文字に変換する関数を追加します。

unvell.ReoGrid.Formula.FormulaExtension.CustomFunctions["myUpper"] =
  (cell, args) =>
  {
    if (args.Length == 0)
    {
      // this function needs at least one argument
      return null;
    }

    return Convert.ToString(args[0]).ToUpper();
  };

数式=myUpper("hello")を入力してこの関数をテストします。 169

Enterを押すと、セルの値が大文字に変換されます。 170

FormulaExtensionについて

FormulaExtensionは、数式計算中に拡張機能を追加するためのインターフェースです。

スクリプト実行機能を持つReoGrid拡張版では、ReoScriptの機能を使用して数式拡張を実装できます。ReoGridの標準版を使用するアプリケーションでは、FormulaExtensionインターフェースが数式拡張機能を実装するより簡単な方法です。

177

CustomFunctionsプロパティは以下のように定義されています。

Dictionary<string, Func<ReoGridCell, object[], object>> CustomFunctions

最も簡単な関数の例

C#:

FormulaExtension.CustomFunctions["myFunc"] = (cell, args) => {
  // function body goes here
  return null;
};

VB.NET:

FormulaExtension.CustomFunctions("myFunc") = Function(cell, args)
    ' function body goes here
    Return Nothing
End Function

デリゲート関数の使用

ラムダ式の代わりに通常のデリゲート関数を使用することもできます。関数を定義するには:

C#

static object MyFunc(ReoGridCell cell, params object[] arguments)
{
  return null;
}

この静的メソッドをカスタム関数として数式で利用可能にするには:

VB.NET

FormulaExtension.CustomFunctions["myFunc"] = MyFunc;

Shared Function MyFunc(cell As ReoGridCell, ParamArray args As Object()) As Object
  Return Nothing
End Function

この共有メソッドをカスタム関数として数式で利用可能にするには:

FormulaExtension.CustomFunctions("myFunc") = AddressOf MyFunc

セルインスタンス

最初の引数は、数式を所有するセルインスタンスです。この関数は数式内から呼び出されます。例:

worksheet["A1"] = "=myFunc()";

セルA1にはカスタム関数「myFunc」を呼び出す数式があります。上で定義した.NETの関数本体が呼び出され、cell引数はA1セルになります。

static object MyFunc(ReoGridCell cell, params object[] arguments)
{
  MessageBox.Show(cell.Position.ToAddress());   // output: A1
  return null;
}

関数からワークシートインスタンスを取得する

セルインスタンスのWorksheetプロパティにアクセスしてワークシートインスタンスを取得し、ワークシートインスタンスのWorkbookプロパティからワークブックを取得します。

FormulaExtension.CustomFunctions["myFunc"] = (cell, args) =>
{
  var worksheet = cell.Worksheet;
  var workbook = worksheet.Workbook;

  ...

  return null;
};

関数のスコープを特定のワークブックまたはワークシートに制限します。

{
  var worksheet = cell.Worksheet;
  var workbook = worksheet.Workbook;

  if (workbook != myWorkbook)
  {
    // not in valid workbook scope
    return null;
  }
}

関数の引数を取得する

2番目の引数には、数式の呼び出し元から渡された引数が含まれます。

FormulaExtension.CustomFunctions["myFunc"] = (cell, args) =>
{
  if (args.Length < 2)
  {
    // this function requires at least two arguments
    return null;
  }

  return null;
};

数式でのデータ型

数式の計算中には以下のデータ型が使用されます。

  • Number(int、long、short、float、double)
  • String(stringおよびStringBuffer)
  • Boolean
  • DateTime
  • Object

ReoGridは数式の計算で常にdoubleを数値型として使用します。ReoGridは値が関数に渡される前に以下の変換を行います。

  • int、long、short、floatはdoubleに変換されます
  • stringおよびStringBufferオブジェクトはstringに変換されます

数値定数

数式で使用される数値定数はdoubleとして初期化されます。例:

worksheet["A1"] = "=myFunc(10)";

数値10はdoubleとして解析されメモリに格納されます。引数配列の最初の要素はdouble型になります。

FormulaExtension.CustomFunctions["myFunc"] = (cell, args) =>
{
  if (args.Length < 1 || !(args[0] is double))
  {
    // this function requires a double value
    return null;
  }
  ...
};

数値変数

セルから数値が取得される場合、doubleに変換されます。以下の関数を作成します。

FormulaExtension.CustomFunctions["myFunc"] = (cell, args) =>
{
  double value = (double)args[0];
  return value \* 2;
};

次に数式で使用します。

sheet["A1"] = (int)10;
sheet["B1"] = "=myFunc(A1)";

データ型変換エラーは発生しません。(ただし、引数の長さには注意してください。)

関数内の参照

セル参照

ReoGridは、数式で使用される参照セルから値を自動的に取得します。「数値変数」の例で示した通りです。

範囲参照

数式で範囲リテラルが使用される場合、ReoGridはRangePosition構造体を関数に渡します。例:

worksheet["G2:K3"] = new object[] { 1, 2, 5, 7, 8, 10, 12, 15, 16, 19};
worksheet["L2"] = "=CountEvenNumber(G2:K3)";

数式で範囲参照(G2:K3)が使用されています。カスタム関数本体内で手動で処理する必要があります。以下の関数例は、指定された範囲内の偶数を数えます。

FormulaExtension.CustomFunctions["CountEvenNumber"] = (cell, args) =>
{
  if (args.Length < 1 || !(args[0] is RangePosition))
  {
    return null; // we need a range reference
  }

  RangePosition range = (RangePosition)args[0];

  int count = 0;

  // iterate over cells inside a range
  cell.Worksheet.IterateCells(range, (r, c, inCell) => {
    double value;

    // try get a number from cell data
    if (ReoGridCellUtility.TryGetNumberData(inCell.Data, out value) {
      if ((value % 2) == 0) {
        count++;
      }
    }

    // continue iterating
    return true;
  });

  return count;
};

名前参照

名前からセルへ

名前参照がセルを指す場合、セルの値が取得されて関数に自動的に渡されます。

worksheet.DefineNamedRange("r1", "A1");
sheet["r1"] = (int)20;
sheet["B1"] = "=myFunc(r1)";

名前から範囲へ

数式で範囲への名前参照が使用される場合、ReoGridはまず名前で範囲を検索し、次にRangePosition構造体を渡します。範囲参照と同様に処理できます。

worksheet.DefineNamedRange("evenRange", "G2:K3");
worksheet["evenRange"] = new object[] { 1, 2, 4, 6, 9, 11, 13, 14, 15, 17 };
worksheet["I2"] = "=CountEvenNumber(evenRange)";
AssertSame(worksheet["I2"], 4);

名前参照プロバイダーのカスタマイズ

.NETコードが提供する定数値を数式で使用することも可能です。以下の例では、異なる定数値を返す2つの名前を追加します。

unvell.ReoGrid.Formula.FormulaExtension.NameReferenceProvider =
  (cell, name) =>
  {
    if (name == "myName1")
      return 10;
    else if (name == "myName2")
      return 20;
    else
      return null;
  };

NameReferenceProviderは以下のように定義されています。

Func<ReoGridCell, string, object> NameReferenceProvider { get; set; }

セルに=myName1を入力して名前1をテストします。 171

この名前は値10を返します。 172

セルに=myName2を入力します。 173

この名前は値20を返します。 174

数学定数の追加

カスタム名前参照プロバイダーを使用して、数学定数を定義することもできます。以下のコードは定数プロバイダーを定義します。

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

そして数式で定数を使用します。

worksheet("A1") = "=MyConst"

結果: 181

カスタム関数とカスタム名前プロバイダーの組み合わせ

カスタム関数内でカスタム名前プロバイダーを使用することもサポートされています。名前は値に変換されて関数に渡されます。

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言語のカスタム関数の追加

ReoScriptモジュール拡張が有効な場合、ReoScript言語を使用してセルデータ、スタイル、罫線、データフォーマットなどを処理できます。ExcelのVBAに似た機能です。ReoScriptは.NET拡張をサポートしており、スクリプトから.NET関数を呼び出すことができます。

ReoGridはReoScriptカスタム拡張関数の呼び出しをサポートしています。

注意: ReoScript言語拡張はFullリリースパッケージでのみ利用可能です。 178

C#でReoScript関数を追加する

コントロールを拡張するカスタム関数を追加します。

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

テスト:

var worksheet = workbook.CurrentWorksheet;

worksheet[2, 1] = "=sqrt(400)";

44

セルをダブルクリックして数式を確認します。 43

カスタム関数はスクリプト内でも使用できます。

ReoScriptコンテキストでのカスタム関数

workbookオブジェクトは、数式とスクリプトの両方で利用可能なグローバルオブジェクトです(JavaScriptのwindowに似ています)。 Custom Function

上記のコードを一度実行してから、数式で使用します。 Using Custom Function

Enterを押します。 View Result of Custom Function

C#でスクリプトを実行して関数を追加する

C#でスクリプトを実行してReoScript関数を作成することも可能です。以下はReoScriptのラムダ式を使用して新しい関数を作成する例です。

grid.RunScript("script.myfunc = data => '[' + data + ']';");

ページの内容は役に立ちましたか?