PowerTools SPREAD for Windows Forms 10.0J
カスタム関数の作成

使用頻度の高い処理が、組み込み関数として存在しない場合、あるいは、複数の組み込み関数を組み合わせて1つの関数にしたい場合、カスタム関数を作成する方法があります。カスタム関数は、組み込み関数と同様に呼び出すことができます。

カスタム関数に、組み込み関数と同じ名前を付けることもできます。その場合、カスタム関数が組み込み関数よりも優先されます。カスタム関数は評価時に動的にリンクされるので、アプリケーションで、既存のカスタム関数を再定義することもできます。

カスタム関数は、FunctionInfoクラスを継承するクラスとして作成します。次のメンバをオーバーライドします。

メンバ 説明
Nameプロパティ 関数の名前
MinArgsプロパティ 関数に指定できる引数の最小値
MaxArgsプロパティ 関数に指定できる引数の最大値
AcceptsErrorメソッド 関数が指定した引数のエラーを許容するかどうか
Evaluateメソッド 関数の処理

数式がカスタム関数を呼び出したとき、引数の個数が、関数のMinArgsおよびMaxArgsプロパティで指定した範囲を超えていると、関数のEvaluateメソッドはスキップされ、結果には「#VALUE!」エラー値が使用されます。

また、カスタム関数で指定された引数がエラー値(#NUM!、#VALUE!、#REF!など)で、関数のAcceptsErrorメソッドがこの引数に対してFalseを返す(引数のエラーを許容しない)場合、関数のEvaluateメソッドはスキップされ、結果には、このエラー値が使用されます。

カスタム関数のEvaluateメソッドは、数式が評価される場所(コンテキスト)に関する情報は受け取りません。カスタム関数で、この関数が評価される行および列の情報を必要とする場合、このための引数をカスタム関数に追加します。関数を呼び出すときに、引数に、行および列の座標を設定する必要があります。

設定方法

  1. FunctionInfoクラスを継承する、カスタム関数を表すクラスを作成します。
  2. 1.で作成したクラスのインスタンスを生成し、SheetViewクラスのAddCustomFunctionメソッドを使用して、シートにこの関数を登録します。
  3. シートの数式で、カスタム関数が使用できるようになります。

サンプルコード

以下、3つのサンプルコードは、それぞれ、カスタム関数の実装例を表しています。

次のCUBEカスタム関数は、数値を3乗します。つまり、CUBE(x)はPOWER(x,3)と同等です。

C#
コードのコピー
public class CubeFunctionInfo : FarPoint.CalcEngine.FunctionInfo
{
    public override string Name { get { return "CUBE"; } }
    public override int MinArgs { get { return 1; } }
    public override int MaxArgs { get { return 1; } }
    public override object Evaluate(object[] args)
    {
        double num = FarPoint.CalcEngine.CalcConvert.ToDouble(args[0]);
        return num * num * num;
    }
}
Visual Basic
コードのコピー
Public Class CubeFunctionInfo
    Inherits FarPoint.CalcEngine.FunctionInfo
    Public Overrides ReadOnly Property Name() As String
        Get
            Return "CUBE"
        End Get
    End Property
    Public Overrides ReadOnly Property MinArgs() As Integer
        Get
            Return 1
        End Get
    End Property
    Public Overrides ReadOnly Property MaxArgs() As Integer
        Get
            Return 1
        End Get
    End Property
    Public Overrides Function Evaluate(args As Object()) As Object
        Dim num As Double = FarPoint.CalcEngine.CalcConvert.ToDouble(args(0))
        Return num * num * num
    End Function
End Class

次のXORカスタム関数は、2つのブール値に対し、排他的論理和演算を実行します。C#における"^"演算子や、VBにおけるXOR演算子と似ています。

C#
コードのコピー
public class XorFunctionInfo : FarPoint.CalcEngine.FunctionInfo
{
    public override string Name { get { return "XOR"; } }
    public override int MinArgs { get { return 2; } }
    public override int MaxArgs { get { return 2; } }
    public override object Evaluate(object[] args)
    {
        bool arg0 = FarPoint.CalcEngine.CalcConvert.ToBool(args[0]);
        bool arg1 = FarPoint.CalcEngine.CalcConvert.ToBool(args[1]);
        return (arg0 || arg1) && (arg0 != arg1);
    }
}
Visual Basic
コードのコピー
Public Class XorFunctionInfo
    Inherits FarPoint.CalcEngine.FunctionInfo
    Public Overrides ReadOnly Property Name() As String
        Get
            Return "XOR"
        End Get
    End Property
    Public Overrides ReadOnly Property MinArgs() As Integer
        Get
            Return 2
        End Get
    End Property
    Public Overrides ReadOnly Property MaxArgs() As Integer
        Get
            Return 2
        End Get
    End Property
    Public Overrides Function Evaluate(args As Object()) As Object
        Dim arg0 As Boolean = FarPoint.CalcEngine.CalcConvert.ToBool(args(0))
        Dim arg1 As Boolean = FarPoint.CalcEngine.CalcConvert.ToBool(args(1))
        Return (arg0 OrElse arg1) AndAlso (arg0 <> arg1)
    End Function
End Class

次のNULLカスタム関数は定数値nullを返します。これは、FALSE()関数が定数値Falseを返すのと似ています。

C#
コードのコピー
public class NullFunctionInfo : FunctionInfo
{
    public override string Name { get { return "NULL"; } }
    public override int MinArgs { get { return 0; } }
    public override int MaxArgs { get { return 0; } }
    public override object Evaluate (object[] args)
    {
        return null;
    }
}
Visual Basic
コードのコピー
Public Class NullFunctionInfo
    Inherits FarPoint.CalcEngine.FunctionInfo
    Public Overrides ReadOnly Property Name() As String
        Get
            Return "NULL"
        End Get
    End Property
    Public Overrides ReadOnly Property MinArgs() As Integer
        Get
            Return 0
        End Get
    End Property
    Public Overrides ReadOnly Property MaxArgs() As Integer
        Get
            Return 0
        End Get
    End Property
    Public Overrides Function Evaluate(args As Object()) As Object
        Return DBNull.Value
    End Function
End Class

次のコードは、これらのカスタム関数を登録します。

C#
コードのコピー
fpSpread1.ActiveSheet.AddCustomFunction(new CubeFunctionInfo());
fpSpread1.ActiveSheet.AddCustomFunction(new XorFunctionInfo());
fpSpread1.ActiveSheet.AddCustomFunction(new NullFunctionInfo());
Visual Basic
コードのコピー
FpSpread1.ActiveSheet.AddCustomFunction(New CubeFunctionInfo())
FpSpread1.ActiveSheet.AddCustomFunction(New XorFunctionInfo())
FpSpread1.ActiveSheet.AddCustomFunction(New NullFunctionInfo())

次のコードは、これらのカスタム関数を使用する数式を、シートに設定します。

C#
コードのコピー
fpSpread1.ActiveSheet.SetFormula(0, 0, "CUBE(5)"); fpSpread1.ActiveSheet.SetFormula(1, 0, "XOR(FALSE,FALSE)"); fpSpread1.ActiveSheet.SetFormula(1, 1, "XOR(TRUE,FALSE)");
fpSpread1.ActiveSheet.SetFormula(1, 2, "XOR(FALSE,TRUE)");
fpSpread1.ActiveSheet.SetFormula(1, 3, "XOR(TRUE,TRUE)");
fpSpread1.ActiveSheet.SetFormula(2, 0, "CHOOSE(1,100,NULL(),300)");
fpSpread1.ActiveSheet.SetFormula(2, 1, "CHOOSE(2,100,NULL(),300)");
fpSpread1.ActiveSheet.SetFormula(2, 2, "CHOOSE(3,100,NULL(),300)");
Visual Basic
コードのコピー
FpSpread1.ActiveSheet.SetFormula(0, 0, "CUBE(5)")
FpSpread1.ActiveSheet.SetFormula(1, 0, "XOR(FALSE,FALSE)")
FpSpread1.ActiveSheet.SetFormula(1, 1, "XOR(TRUE,FALSE)")
FpSpread1.ActiveSheet.SetFormula(1, 2, "XOR(FALSE,TRUE)")
FpSpread1.ActiveSheet.SetFormula(1, 3, "XOR(TRUE,TRUE)")
FpSpread1.ActiveSheet.SetFormula(2, 0, "CHOOSE(1,100,NULL(),300)")
FpSpread1.ActiveSheet.SetFormula(2, 1, "CHOOSE(2,100,NULL(),300)")
FpSpread1.ActiveSheet.SetFormula(2, 2, "CHOOSE(3,100,NULL(),300)")

カスタム関数の引数

既定では、引数は値で渡されます。単一の空白セルはnull値(Visual BasicではNothing)として渡されます。空白ではない単一セルは、ボックス化されたプリミティブ(double、boolean、stringなど)として渡されます。セル範囲はCalcArrayクラスのインスタンスとして渡されます。CalcArrayクラスは、2次元配列の行数および列数を決定するRowCountおよびColumnCountプロパティを備えています。また、配列から1つの値を取得するためのGetValueメソッドを備えています。GetValueメソッドで使用する行および列インデックスは、ゼロから始まります。

引数に、セル参照を渡せるようにするには、FunctionInfoクラスのAcceptsReferenceメソッドをオーバーライドする必要があります。AcceptsReferenceメソッドが、対象の引数に対してTrueを返す場合、単一のセルまたはセル範囲が、CalcReferenceクラスのインスタンスとして渡されます。CalcReferenceクラスは、セル参照の先頭行および列を決定するRowおよびColumnプロパティ、行数および列数を決定するRowCountおよびColumnCountプロパティを備えています。また、セル参照から1つの値を取得するためのGetValueメソッドを備えています。GetValueメソッドで使用する行および列インデックスは、RowおよびColumnプロパティの値から始まります。

サンプルコード

次のサンプルコードでは、指定したセル範囲から、指定した値未満のセル数をカウントする関数を作成します。関数の引数に、対象のセル範囲を表すセル参照を渡せるように実装されています。

C#
コードのコピー
class CountIfLessThanFunctionInfo : FarPoint.CalcEngine.FunctionInfo
{
    public override string Name
    {
        get { return "COUNTIFLESSTHAN"; }
    }
    public override int MinArgs
    {
        get { return 2; }
    }
    public override int MaxArgs
    {
        get { return 2; }
    }
    public override bool AcceptsReference(int i)
    {
        return i == 0;
    }
    public override object Evaluate(object[] args)
    {
        FarPoint.CalcEngine.CalcReference range = args[0] as FarPoint.CalcEngine.CalcReference;
        double criteria = FarPoint.CalcEngine.CalcConvert.ToDouble(args[1]);
        double count = 0.0;
        if (range == null)
            return FarPoint.CalcEngine.CalcError.Value;
        for (int i = range.Row; i < range.Row + range.RowCount; i++)
        {
            for (int j = range.Column; j < range.Column + range.ColumnCount; j++) {
                double cellValue = FarPoint.CalcEngine.CalcConvert.ToDouble(range.GetValue(i, j));
                if (cellValue < criteria)
                    count++;
            }
        }
        return count;
    }    
}
//以下をフォームのコードビハインドに記述します
fpSpread1.ActiveSheet.AddCustomFunction(new CountIfLessThanFunctionInfo());
fpSpread1.ActiveSheet.SetClipValue(0, 0, 2, 3, "0\t0\t1\n1\t1\t1");
fpSpread1.ActiveSheet.SetFormula(0, 4, "COUNTIFLESSTHAN(A1:C2, 1)");
Visual Basic
コードのコピー
Class CountIfLessThanFunctionInfo
    Inherits FarPoint.CalcEngine.FunctionInfo
    Public Overrides ReadOnly Property Name() As String
        Get
            Return "COUNTIFLESSTHAN"
        End Get
    End Property
    Public Overrides ReadOnly Property MinArgs() As Integer
        Get
            Return 2
        End Get
    End Property
    Public Overrides ReadOnly Property MaxArgs() As Integer
        Get
            Return 2
        End Get
    End Property
    Public Overrides Function AcceptsReference(i As Integer) As Boolean
        Return i = 0
    End Function
    Public Overrides Function Evaluate(args As Object()) As Object
        Dim range As FarPoint.CalcEngine.CalcReference = TryCast(args(0), FarPoint.CalcEngine.CalcReference)
        Dim criteria As Double = FarPoint.CalcEngine.CalcConvert.ToDouble(args(1))
        Dim count As Double = 0.0
        If range Is Nothing Then
            Return FarPoint.CalcEngine.CalcError.Value
        End If
        For i As Integer = range.Row To range.Row + (range.RowCount - 1)
            For j As Integer = range.Column To range.Column + (range.ColumnCount - 1)
                Dim cellValue As Double = FarPoint.CalcEngine.CalcConvert.ToDouble(range.GetValue(i, j))
                If cellValue < criteria Then
                    count += 1
                End If
            Next
        Next
        Return count
    End Function
End Class
'以下をフォームのコードビハインドに記述します
FpSpread1.ActiveSheet.AddCustomFunction(New CountIfLessThanFunctionInfo())
FpSpread1.ActiveSheet.SetClipValue(0, 0, 2, 3, "0" & vbTab & "0" & vbTab & "1" & vbLf & "1" & vbTab & "1" & vbTab & "1")
FpSpread1.ActiveSheet.SetFormula(0, 4, "COUNTIFLESSTHAN(A1:C2, 1)")
関連トピック

 

 


© 2004-2017, GrapeCity inc. All rights reserved.