Custom Function Based Filters

  • 8 minutes to read

Overview

You can display a filter based on a custom function in pop-up filter menus and filter editors. For example, the following image shows Black Friday Discount filter based on the corresponding custom function:

NOTE

Run the XtraGrid demo to try out the following custom function-based filters:

  • Is Black Friday Discount filter in the Discount column's pop-up filter menu and filter editor.
  • Is Weekend filter in the Sales Date column's pop-up filter menu and filter editor.
  • Not Begins With filter in the Name column's filter editor.

Custom Function Operands

Filters can be based on a custom function that accepts one (unary function) or two (binary function) operands:

  • the first operand - a field value being processed
  • the second operand - a value against which field values are evaluated (users specify the second operand in the filter editor)

The filter editor supports binary and unary functions; the pop-up filter menus support unary functions only.

How to Implement and Display a Custom Function Based Filter

To create a custom function that can be displayed as a filter, implement the ICustomFunctionDisplayAttributes interface. It extends the ICustomFunctionOperatorBrowsable interface with the following properties:

  • DisplayName — a string value that specifies the filter's caption.
  • Image — an Image, SvgImage or image URI that specifies the filter's glyph.

Next, use the CriteriaOperator.RegisterCustomFunction or CriteriaOperator.RegisterCustomFunctions method to register the implemented function.

Do one of the following to display the corresponding filter in filter menus and the filter editor:

Unary Functions

Unary functions accept the single operand - the field value. Unary function-based filters do not allow users to specify a parameter.

The code below shows how to implement Black Friday Discount function. This is a unary function that evaluates to true if the operand is more than or equals 0.15.

NOTE

Run the XtraGrid demo and click Open Solution for the complete example.

using DevExpress.Data.Filtering;

IsBlackFridayDiscountFunction.Register();
gridView1.QueryCustomFunctions += OnQueryCustomFunctions;

void OnQueryCustomFunctions(object sender, Data.Filtering.CustomFunctionEventArgs e) {
    if(e.PropertyName == "Discount")
        e.Add(IsBlackFridayDiscountFunction.FunctionName);
}

public class IsBlackFridayDiscountFunction : ICustomFunctionDisplayAttributes {
    public const string FunctionName = "IsBlackFridayDiscount";
    static readonly IsBlackFridayDiscountFunction Instance = new IsBlackFridayDiscountFunction();
    IsBlackFridayDiscountFunction() { }
    public static void Register() {
        CriteriaOperator.RegisterCustomFunction(Instance);
    }
    public static bool Unregister() {
        return CriteriaOperator.UnregisterCustomFunction(Instance);
        }
    #region ICustomFunctionOperatorBrowsable Members
    public FunctionCategory Category {
        get { return FunctionCategory.Math; }
    }
    public string Description {
        get { return "The discount amount is 15% or more."; }
    }
    public bool IsValidOperandCount(int count) {
        return count == 1;
    }
    public bool IsValidOperandType(int operandIndex, int operandCount, Type type) {
        return DevExpress.Data.Summary.SummaryItemTypeHelper.IsNumericalType(type);
    }
    public int MaxOperandCount {
        get { return 1; }
    }
    public int MinOperandCount {
        get { return 1; }
    }
    #endregion
    #region ICustomFunctionDisplayAttributes
    public string DisplayName {
        get { return "Is Black Friday Discount"; }
    }
    public object Image {
        get { return "bo_price"; }
    }
    #endregion
    #region ICustomFunctionOperator Members
    //The single opearand (operands[0]) is the field value being processed.
    public object Evaluate(params object[] operands) {
        double discount = Convert.ToDouble(operands[0]);
        return discount >= 0.15;
    }
    public string Name {
        get { return FunctionName; }
    }
    public Type ResultType(params Type[] operands) {
        return typeof(bool);
   }
    #endregion
}

Binary Functions

Binary functions accept the second operand - a user-specified parameter. Binary function-based filters can only be displayed in the filter editor.

The code below shows how to implement Not Begins With function. This is a binary function that evaluates to true if the first operand (the field value) not starts with the second operand (the value specified in the filter editor).

NOTE

Run the XtraGrid demo and click Open Solution for the complete example.

using DevExpress.Data.Filtering;

NotBeginsWithFunction.Register();
CriteriaOperator.QueryCustomFunctions += OnQueryCustomUIFunctions;

static void OnQueryCustomUIFunctions(object sender, CustomFunctionEventArgs e) {
    if(e.PropertyType == typeof(string))
        e.Add(NotBeginsWithFunction.FunctionName);
}

public class NotBeginsWithFunction : ICustomFunctionDisplayAttributes {
    public const string FunctionName = "NotBeginsWith";
    static readonly NotBeginsWithFunction Instance = new NotBeginsWithFunction();
    NotBeginsWithFunction() { }
    //
    public static void Register() {
        CriteriaOperator.RegisterCustomFunction(Instance);
    }
    public static bool Unregister() {
        return CriteriaOperator.UnregisterCustomFunction(Instance);
    }
    #region ICustomFunctionOperatorBrowsable Members
    public FunctionCategory Category {
        get { return FunctionCategory.Text; }
    }
    public string Description {
        get { return "Selects items that do not start with the specified string."; }
    }
    public bool IsValidOperandCount(int count) {
        return count == 2;
    }
    public bool IsValidOperandType(int operandIndex, int operandCount, Type type) {
        return type == typeof(string);
    }
    public int MaxOperandCount {
        get { return 2; }
    }
    public int MinOperandCount {
        get { return 2; }
    }
    #endregion
    #region ICustomFunctionDisplayAttributes
    public string DisplayName {
        get { return "Not Begins With"; }
    }
    public object Image {
        get { return null; }
    }
    #endregion
    #region ICustomFunctionOperator Members
    //The first operand (operands[0]) is the field value being processed.
    //The second operand (operands[1]) is the value specified in the filter editor.
    public object Evaluate(params object[] operands) {
        if(operands[0] != null && operands[1] != null) {
            string str1 = operands[0].ToString(); string str2 = operands[1].ToString();
            return !str1.StartsWith(str2, StringComparison.InvariantCultureIgnoreCase);
        }
        return false;
    }
    public string Name {
        get { return FunctionName; }
    }
    public Type ResultType(params Type[] operands) {
        return typeof(bool);
    }
    #endregion
}