Custom Functions
The following sections describe the possible approaches for creating a custom function:
Inheriting FunctionBase Abstract Class
The document model provides a powerful API for creating custom functions. All functions must inherit from the abstract FunctionBase class, which provides basic methods and properties for each function instance.
The following are the basic FunctionBase members:
-
Name: Property of typeStringthat defines the name of the function. The property is used for registering the function, so the name must be unique (case insensitive). If a function with a repeating name is registered, it overrides the previous function registered with this name. -
FunctionInfo: Property of typeFunctionInfothat provides a description of the function and its arguments. For more information, see FunctionInfo. -
ArgumentConversionRules: Property describing how different argument types are interpreted. The functions API works with five argument types (Logical, Number, Text, Reference, and Array) and each function may interpret each of these argument types differently. For more information, see ArgumentConversionRules. -
EvaluateandEvaluateOverridemethods: The methods where the function calculations take place. To define a custom function, override theEvaluateOverridemethod so that you can later obtain the function calculation value through theEvaluatemethod.
Additionally, each custom function needs to be registered through the FunctionManager class. Pass an instance of the function class to the static Register() method.
Example 1 shows how to register a function class ArgumentsFunction, an inheritor of FunctionBase.
Example 1: Register Custom Function
FunctionManager.RegisterFunction(new ArgumentsFunction());
Functions Inheritance Tree
The document model provides an inheritance tree of classes that offer ready-to-use features for different function types, depending on the function arguments and the desired result.
Figure 1 shows the base abstract function classes.
Figure 1: Functions Inheritance

-
FunctionBase: Provides the base function properties (Name,FunctionInfo,ArgumentConversionRules). Also provides the logic of theIsArgumentNumberValid()method which handles the scenario when an invalid arguments count is passed by the user. By inheritingFunctionBaseyou must override theEvaluateOverride(RadExpression[] arguments)method, so you need to handle the full logic of convertingRadExpressionarguments to function arguments. -
FunctionWithArguments: Handles the basic logic of converting aRadExpressionvalue to another value type corresponding to theArgumentTypedefined in theFunctionInfoproperty. By inheriting from this class, you need to override theEvaluateOverride(object[] arguments)method and handle an array of already converted function argument values. -
FunctionWithSameTypeArguments<T>: By inheriting this class, you need to override theEvaluateOverride(T[] arguments)method and handle an array of arguments with the same type T. -
StringInFunctions,NumbersInFunction,BooleansInFunction: These classes inherit directly fromFunctionWithSameTypeArguments<String>,FunctionWithSameTypeArguments<double>, andFunctionWithSameTypeArguments<bool>. Use them when the function requires the respective argument type (String, double, or Boolean).
ArgumentConversionRules
The ArgumentConversionRules class provides properties that describe how different function argument types are interpreted. The functions API works with five argument types (Logical, Number, Text, Reference, and Array) and each function may interpret each of these argument types differently. Additionally, RadSpreadProcessing differentiates between direct arguments (values passed directly into the formula) and indirect arguments (values that depend on some other cells referencing).
ArgumentConversionRules has the following properties:
-
EmptyDirectArgument: TheArgumentInterpretationof an Empty cell value, passed as a direct argument. -
NumberDirectArgument: TheArgumentInterpretationof a Number cell value, passed as a direct argument. -
BoolDirectArgument: TheArgumentInterpretationof a Boolean cell value, passed as a direct argument. -
TextNumberDirectArgument: TheArgumentInterpretationof a String cell value that can be parsed to a number, passed as a direct argument. -
NonTextNumberDirectArgument: TheArgumentInterpretationof a String cell value that cannot be parsed to a number, passed as a direct argument. -
EmptyIndirectArgument: TheArgumentInterpretationof an Empty cell value, passed as an indirect argument. -
NumberIndirectArgument: TheArgumentInterpretationof a Number cell value, passed as an indirect argument. -
BoolIndirectArgument: TheArgumentInterpretationof a Boolean cell value, passed as an indirect argument. -
TextNumberIndirectArgument: TheArgumentInterpretationof a String cell value that can be parsed to a number, passed as an indirect argument. -
NonTextNumberIndirectArgument: TheArgumentInterpretationof a String cell value that cannot be parsed to a number, passed as an indirect argument. -
ArrayArgument: TheArrayArgumentInterpretation.
The values of these properties come from the ArgumentInterpretation and ArrayArgumentInterpretation enumerations and are set through the constructor of ArgumentConversionRules. The default values of these interpretations in the constructor are ArgumentInterpretation.UseAsIs and ArrayArgumentInterpretation.UseFirstElement.
Example 2 creates an instance of ArgumentConversionRules:
Example 2: Create ArgumentConversionRules
public static readonly ArgumentConversionRules BoolFunctionConversion = new ArgumentConversionRules(
emptyIndirectArgument: ArgumentInterpretation.Ignore,
textNumberDirectArgument: ArgumentInterpretation.TreatAsError,
textNumberIndirectArgument: ArgumentInterpretation.Ignore,
nonTextNumberDirectArgument: ArgumentInterpretation.TreatAsError,
nonTextNumberIndirectArgument: ArgumentInterpretation.Ignore,
arrayArgument: ArrayArgumentInterpretation.UseAllElements);
FunctionInfo
The FunctionInfo class provides properties that describe the purpose of the function and each of its arguments.
FunctionInfo has the following properties:
-
Category: TheFunctionCategoryto which the function belongs. -
Description: Description of the function as a string value. -
RequiredArgumentsCount: Returns the number of required arguments of the function. If the user passes fewer arguments than theRequiredArgumentsCount, an error is raised. -
OptionalArgumentsCount: Returns the count of the optional arguments group. -
OptionalArgumentsRepetitionCount: Returns the number of repetitions of the optional group. The valid count of all arguments depends on this value by satisfying the following conditions: -
When
OptionalArgumentsRepetitionCount <= 1: -
ValidArgumentsCount >= RequiredArgumentsCount -
ValidArgumentsCount <= RequiredArgumentsCount + OptionalArgumentsCount -
When
OptionalArgumentsRepetitionsCount > 1: -
ValidArgumentsCount = RequiredArgumentsCount + i * OptionalArgumentsCount -
i >= 0 -
i <= OptionalArgumentsRepetitionsCount -
i is integer number -
IsDefaultValueFunction: Returns a Boolean value that indicates whether the function is a default value function. -
When
true: The function returns some default value when all passed values haveArgumentInterpretation.IgnoreinArgumentConversionRulesof the function. -
When
false: The function returnsErrorExpressions.ValueErrorwhen all passed values are not valid, even if they haveArgumentInterpretation.IgnoreinArgumentConversionRulesof the function. -
Format: Returns theCellValueFormatof the function result, if the result needs specific formatting (for example, DateTime or Currency).
Example 3 shows how to create an instance of the FunctionInfo class.
Example 3: Create FunctionInfo
static string functionName = "ADD";
static string description = "Adds all the numbers in range of cells.";
static IEnumerable<ArgumentInfo> requiredArguments = new ArgumentInfo[]
{
new ArgumentInfo("Number", "number1, number2,... are the numbers to sum. Logical values and text are ignored in cells, included if typed as arguments.", ArgumentType.Number),
};
static IEnumerable<ArgumentInfo> optionalArguments = new ArgumentInfo[]
{
new ArgumentInfo("Number", "number1, number2,... are the numbers to sum. Logical values and text are ignored in cells, included if typed as arguments.", ArgumentType.Number),
};
FunctionInfo sumFunctionInfo = new FunctionInfo(functionName, FunctionCategory.MathTrig, description, requiredArguments, optionalArguments, 254, true);
Custom Function Examples
The following example defines a custom function named "ARGUMENTS" that inherits from the FunctionBase class. In the FunctionInfo definition, the function has three required arguments and three optional arguments with optionalArgumentsRepeatsCount equal to 3.
The result of the function calculations is the number of arguments passed to the function, as shown in the EvaluateOverride() method.
Example 4 shows how to create the "ARGUMENTS" function.
Example 4: Create ARGUMENTS Function
public class ArgumentsFunction : FunctionBase
{
public static readonly string FunctionName = "ARGUMENTS";
private static readonly FunctionInfo Info;
public override string Name
{
get
{
return FunctionName;
}
}
public override FunctionInfo FunctionInfo
{
get
{
return Info;
}
}
static ArgumentsFunction()
{
string description = "Returns number of used arguments.";
IEnumerable<ArgumentInfo> requiredArguments = new ArgumentInfo[]
{
new ArgumentInfo("First", "First argument.", ArgumentType.Any),
new ArgumentInfo("Second", "Second argument.", ArgumentType.Any),
new ArgumentInfo("Third", "Third argument.", ArgumentType.Any),
};
IEnumerable<ArgumentInfo> optionalArguments = new ArgumentInfo[]
{
new ArgumentInfo("First", "First argument.", ArgumentType.Any),
new ArgumentInfo("Second", "Second argument.", ArgumentType.Any),
new ArgumentInfo("Third", "Third argument.", ArgumentType.Any),
};
Info = new FunctionInfo(FunctionName, FunctionCategory.MathTrig, description, requiredArguments, optionalArguments, optionalArgumentsRepeatCount: 3);
}
protected override RadExpression EvaluateOverride(FunctionEvaluationContext<RadExpression> context)
{
return new NumberExpression(context.Arguments.Length);
}
}
The following example defines a custom function named "E" that inherits from the FunctionBase class. The function takes no arguments and always returns the Napier constant.
Example 5 shows how to create the "E" function.
Example 5: Create E Function
public class E : FunctionBase
{
public static readonly string FunctionName = "E";
private static readonly FunctionInfo Info;
public override string Name
{
get
{
return FunctionName;
}
}
public override FunctionInfo FunctionInfo
{
get
{
return Info;
}
}
static E()
{
string description = "Returns the Napier's constant.";
Info = new FunctionInfo(FunctionName, FunctionCategory.MathTrig, description);
}
protected override RadExpression EvaluateOverride(FunctionEvaluationContext<RadExpression> context)
{
return NumberExpression.E;
}
}
You can download a runnable project with the previous and several other custom function examples from the SDK repository on GitHub.