Custom User-Defined Functions (UDF)

This module uses the DevExpress Spreadsheet API to demonstrate custom function functionality (User-Defined Functions). The custom function in this example ("SPHEREMASS") calculates the mass of a sphere based on its radius and material density. The function uses the following formula: mass = (4/3) × π × r³ × density.

You can use such custom calculations to extend your worksheet's functionality beyond the standard built-in functions.

Use the Create Document and Save as... dropdown button to select the output format, generate the document with an embedded custom function, and download the result. Note that Microsoft Excel will not re-calculate custom functions created in such manner. You can use these functions when editing documents in code.

This module creates an Excel document that uses a custom "SPHEREMASS" User-Defined Function (UDF).

This function uses the following formula to calculate sphere mass based on radius and material density:

mass = (4/3) * π * r^3 * density



using DevExpress.Spreadsheet;
using DevExpress.Spreadsheet.Functions;
using System.Globalization;

public Stream CreateWorkbookWithCustomFunction(DocumentFormat outputFormat) {
    using Workbook workbook = new Workbook();

    // Create a custom function and add it to the global Workbook scope
    SphereMassFunction customFunction = new SphereMassFunction();
    var globalFunctions = workbook.Functions.GlobalCustomFunctions;
    if(!globalFunctions.Contains(customFunction.Name))
        globalFunctions.Add(customFunction);

    workbook.BeginUpdate();
    try {
        // Use the first worksheet
        Worksheet worksheet = workbook.Worksheets.First();
        worksheet.Name = "Custom User-Defined Functions";
        // Set cell widths and alignment
        worksheet.Range["A1:H1"].ColumnWidthInCharacters = 12;
        worksheet.Range["A1:H1"].Alignment.Horizontal = SpreadsheetHorizontalAlignment.Center;

        // Define a named range for seawater density
        worksheet.DefinedNames.Add("seawater", "1025");

        // Initialize worksheet data
        worksheet["A1"].Value = "Radius, m";
        worksheet["B1"].Value = "Material";
        worksheet["C1"].Value = "Mass, kg";
        worksheet["D1"].Value = "Function Result";

        worksheet["A2"].Value = 0.1;
        worksheet["B2"].Value = "";
        worksheet["C2"].FormulaInvariant = "=SPHEREMASS(A2)";
        worksheet["C2"].NumberFormat = "#.##";

        worksheet["A3"].Value = 0.1;
        worksheet["B3"].Value = "Seawater";
        worksheet["C3"].FormulaInvariant = "=SPHEREMASS(A3, seawater)";
        worksheet["C3"].NumberFormat = "#.##";

        worksheet["A5"].Value = "Note: Excel can't calculate custom user-defined functions. Cells \"C2\" and \"C3\" display the '#NAME?' after recalculation attempts.";
        worksheet["A6"].Value = "The results of the custom SPHEREMASS function calculation are displayed in cells \"D2\" and \"D3\".";

        // Calculate worksheet to evaluate formulas
        worksheet.Calculate();

        // Display the results of the custom function calculation in the "D2" and "D3" cells
        worksheet["D2"].NumberFormat = "#.##";
        worksheet["D2"].Value = worksheet["C2"].Value;

        worksheet["D3"].NumberFormat = "#.##";
        worksheet["D3"].Value = worksheet["C3"].Value;

        // Auto-fit columns
        worksheet.Columns.AutoFit("B", "D");
    } finally {
        workbook.EndUpdate();
    }

    // Create output stream
    var outputStream = new MemoryStream();

    // Save document in target format
    workbook.SaveDocument(outputStream, outputFormat);

    outputStream.Seek(0, SeekOrigin.Begin);
    return outputStream;
}

// Custom SPHEREMASS function implementation
public class SphereMassFunction : ICustomFunction {
    const string functionName = "SPHEREMASS";
    readonly ParameterInfo[] functionParameters;

    public SphereMassFunction() {
        // Missing optional parameters do not result in an error message
        this.functionParameters =
            new ParameterInfo[] {
                new ParameterInfo(ParameterType.Value, ParameterAttributes.Required),
                new ParameterInfo(ParameterType.Value, ParameterAttributes.Optional)
            };
    }
    public string Name { get { return functionName; } }
    ParameterInfo[] IFunction.Parameters { get { return functionParameters; } }
    ParameterType IFunction.ReturnType { get { return ParameterType.Value; } }
    bool IFunction.Volatile { get { return false; } }

    ParameterValue IFunction.Evaluate(IList<ParameterValue> parameters, EvaluationContext context) {
        double radius;
        double density = 1000;
        ParameterValue radiusParameter;
        ParameterValue densityParameter;

        if(parameters.Count == 2) {
            densityParameter = parameters[1];
            if(densityParameter.IsError)
                return densityParameter;
            else
                density = densityParameter.NumericValue;
        }

        radiusParameter = parameters[0];
        if(radiusParameter.IsError)
            return radiusParameter;
        else
            radius = radiusParameter.NumericValue;

        return (4 * Math.PI) / 3 * Math.Pow(radius, 3) * density;
    }
    string IFunction.GetName(CultureInfo culture) {
        return functionName;
    }
}