Dev Express bietet selbst Erweiterungen an: Custom Functions Dev Express

Diese Möglichkeiten sind für den Einsatz in Business App nicht ausreichend. Da hier die Anforderung besteht komplexe oder variable Criteria Operators für die Konfiguration zu vereinfachen. Dafür wird eine Criteria Operators Funktion implementiert, die als Ergebnis selbst wieder einen Criteria Operator zurückliefert.

Implementierung eigener Funktionen

Ziel unserer Erweiterung von Custom Criteria Operators Funktionen ist es Teile eines Criteria Operator Ausdrucks zu ersetzen. Entsprechende Erweiterungen im Core befinden sich im Packet BA.Core.CriteriaOperators.Functions.

Um eine Erweiterung zu implementieren, muss das Interface ICriteriaOperatorBAFunction implementiert werden. Dieses erweitert das Interface ICustomFunctionOperator von Dev Express. Wird das BA eigene Interface, implementiert werden diese automatisiert beim Starten der Anwendung registriert.

Die Interface Methode GetCriteriaDB muss implementiert werden und ersetzt im Criteria Operator Ausdruck die eigene Funktion durch den Rückgabewert. Die Operanden sollten auf ihre Gültigkeit validiert und bei Fehlern Exceptions geworfen werden. Damit wird sichergestellt, dass beim Parsen entsprechende Fehler an den Konfigurator weitergegeben werden.

Zusätzlich müssen folgende Interface-Teile implementiert werden.

  • ICustomFunctionOperator.Name definiert den Namen innerhalb eines Criteria Operators. Hierbei sollte mit entsprechenden Präfixen gearbeitet werden, um Kollisionen zu vermeiden.
  • ICustomFunctionOperator.ResultType Definiert den Rückgabewert.
  • ICustomFunctionOperator.Evaluate Wird benötigt, wenn in .Net die Evaluate Methode ausgeführt wird.
  • ICustomFunctionOperator.Convert Wird benötigt, wenn von .Net Expression unterstützt werden soll.

Beispiel:

In diesem Beispiel wird ein neuer Operator “BATMyText” mit einem String Parameter definiert. Dieser Operator gibt den Parameter String unverändert zurück.

Iif([BooleanField], [TextField], BATMyText('Mein Text'))
public class MyTextOperator : ICriteriaOperatorBAFunction
{
    public const string Name = "BATMyText";

    string ICustomFunctionOperator.Name => Name;

    public Type ResultType(params Type[] operands) => typeof(string);

    public virtual Expression Convert(ICriteriaToExpressionConverter converter, params Expression[] operands)
    {
        if (operands.Length == 1 && operands[0].Type == typeof(string))
            return Expression.Default(typeof(string));

        throw new ArgumentException("Die Funktion BATMyText benötigt einen Parameter");
    }

    public virtual object Evaluate(params object[] operands)
    {
        if (operands.Length == 1 && operands[0] is string operand1)
            return operand1;

        throw new ArgumentException("Die Funktion BATMyText benötigt einen Parameter");
    }

    public virtual CriteriaOperator GetCriteriaDB(FunctionOperator function)
    {
        if (function.Operands.Count == 2 && function.Operands[1] is OperandValue value && value.Value is string operand1)
            return new OperandValue(operand1);

        throw new ArgumentException("Die Funktion BATMyText benötigt einen Parameter");
    }
}

Funktionen in der Programmierung

Um Funktionen von Dev Express per Programmierung zu definieren, muss ein FunctionOperator erstellt werden.

FunctionOperator dayOfYear = new FunctionOperator(FunctionOperatorType.GetDayOfYear, new OperandProperty("DateField"));

In diesem Fall wird der Tag des Jahres eines Datumwertes ermittelt. In dem Beispiel ist zu beachten, das in BA die Datumswerte immer in UTC abgespeichert werden. Anstatt wie im Beispiel den Datumswert korrekt zu erhalten, muss dieser in die aktuelle Zeitzone umgewandelt werden. Dies dient hier als Beispiel wie Eigene Funktionen bei der programmatischen Definition von Formeln genutzt werden.

FunctionOperator dateValue = new FunctionOperator(ToCurrentTimeZoneOperator.Name, new OperandProperty("DateField"));
FunctionOperator dayOfYear = new FunctionOperator(FunctionOperatorType.GetDayOfYear, dateValue);