Example T546944
Visible to All Users

Grid View for ASP.NET Web Forms - How to apply custom function filter criteria operators

This example demonstrates how to use a CriteriaPatchBase class descendant to apply a custom function criteria operator.

Custom function filter criteria operator

Overview

Assign a custom function operator to the grid's FilterExpression property. For the auto filter row, handle the grid's server-side ProcessColumnAutoFilter event as follows:

C#
protected void Grid_ProcessColumnAutoFilter(object sender, DevExpress.Web.ASPxGridViewAutoFilterEventArgs e) { var grid = (ASPxGridView)sender; if(e.Column.FieldName == SpecialFilterColumnFieldName && e.Kind == GridViewAutoFilterEventKind.CreateCriteria) { grid.FilterExpression = UpdateGridFilterExpression(grid, e); e.Criteria = null; } }

Handle the grid's server-side AutoFilterCellEditorInitialize event to assign the custom criteria operator value to the filter editor.

C#
protected void Grid_AutoFilterCellEditorInitialize(object sender, ASPxGridViewEditorEventArgs e) { var grid = (ASPxGridView)sender; if(e.Column.FieldName == SpecialFilterColumnFieldName) { var gridCriteria = CriteriaOperator.Parse(grid.FilterExpression); e.Editor.Value = CriteriaVisitor.GetCustomFunctionOperatorValue(gridCriteria, e.Column.FieldName); } }

Files to Review

Documentation

Example Code

App_Code/CriteriaPatcherBase.cs(vb)
C#
using DevExpress.Data.Filtering; public class CriteriaPatcherBase : IClientCriteriaVisitor<CriteriaOperator> { protected CriteriaPatcherBase() { } protected CriteriaOperator AcceptOperator(CriteriaOperator theOperator) { if (IsNull(theOperator)) return null; return theOperator.Accept<CriteriaOperator>(this); } protected CriteriaOperatorCollection VisitOperands(CriteriaOperatorCollection operands) { bool isModified = false; CriteriaOperatorCollection result = new CriteriaOperatorCollection(operands.Count); foreach (CriteriaOperator operand in operands) { CriteriaOperator acceptedOperand = this.AcceptOperator(operand); result.Add(acceptedOperand); if (!object.ReferenceEquals(operand, acceptedOperand)) isModified = true; } return isModified ? result : operands; } protected static bool IsNull(CriteriaOperator theOperator) { return object.ReferenceEquals(theOperator, null); } protected virtual CriteriaOperator VisitJoin(JoinOperand theOperand) { CriteriaOperator aggregatedExpression = this.AcceptOperator(theOperand.AggregatedExpression); CriteriaOperator condition = this.AcceptOperator(theOperand.Condition); if (object.ReferenceEquals(theOperand.AggregatedExpression, aggregatedExpression) && object.ReferenceEquals(theOperand.Condition, condition)) return theOperand; return new JoinOperand(theOperand.JoinTypeName, condition, theOperand.AggregateType, aggregatedExpression); } protected virtual CriteriaOperator VisitProperty(OperandProperty theOperand) { return theOperand; } protected virtual CriteriaOperator VisitAggregate(AggregateOperand theOperand) { CriteriaOperator aggregatedExpression = this.AcceptOperator(theOperand.AggregatedExpression); CriteriaOperator condition = this.AcceptOperator(theOperand.Condition); if (object.ReferenceEquals(theOperand.AggregatedExpression, aggregatedExpression) && object.ReferenceEquals(theOperand.Condition, condition)) return theOperand; return new AggregateOperand(theOperand.CollectionProperty, aggregatedExpression, theOperand.AggregateType, condition); } protected virtual CriteriaOperator VisitFunction(FunctionOperator theOperator) { CriteriaOperatorCollection operands = this.VisitOperands(theOperator.Operands); if (object.ReferenceEquals(theOperator.Operands, operands)) return theOperator; return new FunctionOperator(theOperator.OperatorType, operands); } protected virtual CriteriaOperator VisitValue(OperandValue theOperand) { return theOperand; } protected virtual CriteriaOperator VisitGroup(GroupOperator theOperator) { CriteriaOperatorCollection operands = this.VisitOperands(theOperator.Operands); if (object.ReferenceEquals(theOperator.Operands, operands)) return theOperator; return new GroupOperator(theOperator.OperatorType, operands); } protected virtual CriteriaOperator VisitIn(InOperator theOperator) { CriteriaOperator leftOperand = this.AcceptOperator(theOperator.LeftOperand); CriteriaOperatorCollection operands = this.VisitOperands(theOperator.Operands); if (object.ReferenceEquals(theOperator.LeftOperand, leftOperand) && object.ReferenceEquals(theOperator.Operands, operands)) return theOperator; return new InOperator(leftOperand, operands); } protected virtual CriteriaOperator VisitUnary(UnaryOperator theOperator) { CriteriaOperator operand = this.AcceptOperator(theOperator.Operand); if (object.ReferenceEquals(theOperator.Operand, operand)) return theOperator; return new UnaryOperator(theOperator.OperatorType, operand); } protected virtual CriteriaOperator VisitBinary(BinaryOperator theOperator) { CriteriaOperator leftOperand = this.AcceptOperator(theOperator.LeftOperand); CriteriaOperator rightOperand = this.AcceptOperator(theOperator.RightOperand); if (object.ReferenceEquals(theOperator.LeftOperand, leftOperand) && object.ReferenceEquals(theOperator.RightOperand, rightOperand)) return theOperator; return new BinaryOperator(leftOperand, rightOperand, theOperator.OperatorType); } protected virtual CriteriaOperator VisitBetween(BetweenOperator theOperator) { CriteriaOperator beginExpression = this.AcceptOperator(theOperator.BeginExpression); CriteriaOperator endExpression = this.AcceptOperator(theOperator.EndExpression); CriteriaOperator testExpression = this.AcceptOperator(theOperator.TestExpression); if (object.ReferenceEquals(theOperator.BeginExpression, beginExpression) && object.ReferenceEquals(theOperator.EndExpression, endExpression) && object.ReferenceEquals(theOperator.TestExpression, testExpression)) return theOperator; return new BetweenOperator(testExpression, beginExpression, endExpression); } #region IClientCriteriaVisitor CriteriaOperator IClientCriteriaVisitor<CriteriaOperator>.Visit(JoinOperand theOperand) { return this.VisitJoin(theOperand); } CriteriaOperator IClientCriteriaVisitor<CriteriaOperator>.Visit(OperandProperty theOperand) { return this.VisitProperty(theOperand); } CriteriaOperator IClientCriteriaVisitor<CriteriaOperator>.Visit(AggregateOperand theOperand) { return this.VisitAggregate(theOperand); } #endregion #region ICriteriaVisitor CriteriaOperator ICriteriaVisitor<CriteriaOperator>.Visit(FunctionOperator theOperator) { return this.VisitFunction(theOperator); } CriteriaOperator ICriteriaVisitor<CriteriaOperator>.Visit(OperandValue theOperand) { return this.VisitValue(theOperand); } CriteriaOperator ICriteriaVisitor<CriteriaOperator>.Visit(GroupOperator theOperator) { return this.VisitGroup(theOperator); } CriteriaOperator ICriteriaVisitor<CriteriaOperator>.Visit(InOperator theOperator) { return this.VisitIn(theOperator); } CriteriaOperator ICriteriaVisitor<CriteriaOperator>.Visit(UnaryOperator theOperator) { return this.VisitUnary(theOperator); } CriteriaOperator ICriteriaVisitor<CriteriaOperator>.Visit(BinaryOperator theOperator) { return this.VisitBinary(theOperator); } CriteriaOperator ICriteriaVisitor<CriteriaOperator>.Visit(BetweenOperator theOperator) { return this.VisitBetween(theOperator); } #endregion }
App_Code/CriteriaVisitor.cs(vb)
C#
using DevExpress.Data.Filtering; using System; using System.Linq; public class CriteriaVisitor : CriteriaPatcherBase { enum CustomVisitMode { LookingOnlyForCustomOperator, RemoveCustomOperator } public static CriteriaOperator RemoveCustomFunction(CriteriaOperator theOperator, string fieldName) { return new CriteriaVisitor(fieldName, CustomVisitMode.RemoveCustomOperator).AcceptOperator(theOperator); } public static string GetCustomFunctionOperatorValue(CriteriaOperator theOperator, string fieldName) { var myFunctionOperator = new CriteriaVisitor(fieldName, CustomVisitMode.LookingOnlyForCustomOperator).AcceptOperator(theOperator) as FunctionOperator; if(!IsNull(myFunctionOperator)) return ((ConstantValue)myFunctionOperator.Operands[1]).Value.ToString(); return null; } CriteriaVisitor(String fieldName, CustomVisitMode visitMode) { FieldName = fieldName; VisitMode = visitMode; } protected string FieldName { get; private set; } CustomVisitMode VisitMode { get; set; } protected override CriteriaOperator VisitFunction(FunctionOperator theOperator) { if(IsMyCustomFunctionOperator(theOperator)) return VisitMode == CustomVisitMode.LookingOnlyForCustomOperator ? theOperator : null; if(VisitMode == CustomVisitMode.RemoveCustomOperator) return base.VisitFunction(theOperator); return null; } protected override CriteriaOperator VisitGroup(GroupOperator theOperator) { var operands = VisitOperands(theOperator.Operands).Where(op => !IsNull(op)); if(VisitMode == CustomVisitMode.LookingOnlyForCustomOperator) return operands.FirstOrDefault(op => IsMyCustomFunctionOperator(op as FunctionOperator)); return new GroupOperator(theOperator.OperatorType, operands); } protected bool IsMyCustomFunctionOperator(FunctionOperator criteria) { if(IsNull(criteria) || criteria.OperatorType != FunctionOperatorType.Custom) return false; var operands = criteria.Operands; if(operands.Count != 4) return false; var customFunctionName = operands[0] as ConstantValue; var stateOperand = operands[1] as OperandValue; var columnOperand = operands[2] as OperandProperty; if(IsNull(customFunctionName) || IsNull(stateOperand) || IsNull(columnOperand)) return false; return customFunctionName.Value.ToString() == MyCustomFunctionOperator.Name && columnOperand.PropertyName == FieldName; } }
App_Code/MyCustomFunctionOperator.cs(vb)
C#
using DevExpress.Data.Filtering; using System; public class MyCustomFunctionOperator : ICustomFunctionOperator { public static string Name { get { return "MyFunctionOperator"; } } object ICustomFunctionOperator.Evaluate(params object[] operands) { if(operands.Length == 3) { var state = operands[0] as string; if(!string.IsNullOrEmpty(state)) { var shippedDate = !ReferenceEquals(operands[1], null) ? Convert.ToDateTime(operands[1]) : DateTime.MaxValue; var requiredDate = !ReferenceEquals(operands[2], null) ? Convert.ToDateTime(operands[2]) : DateTime.MaxValue; switch(state) { case "OK": return shippedDate <= requiredDate; case "NOTOK": return shippedDate > requiredDate && shippedDate != DateTime.MaxValue; case "ISSUE": return shippedDate == DateTime.MaxValue; } } } return true; } string ICustomFunctionOperator.Name { get { return Name; } } Type ICustomFunctionOperator.ResultType(params Type[] operands) { return typeof(bool); } }
Default.aspx
ASPx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <%@ Register Assembly="DevExpress.Web.v16.2, Version=16.2.17.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" Namespace="DevExpress.Web" TagPrefix="dx" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>ASPxGridView - How to apply Custom Function Filter Criteria Operator</title> </head> <body> <h2>ASPxGridView - How to apply Custom Function Filter Criteria Operator</h2> <form id="form1" runat="server"> <div> <dx:ASPxGridView ID="Grid" runat="server" DataSourceID="SqlDataSource1" OnAutoFilterCellEditorCreate="Grid_AutoFilterCellEditorCreate" OnAutoFilterCellEditorInitialize="Grid_AutoFilterCellEditorInitialize" OnProcessColumnAutoFilter="Grid_ProcessColumnAutoFilter"> <Columns> <dx:GridViewDataTextColumn FieldName="ShipName" /> <dx:GridViewDataTextColumn FieldName="ProductName" /> <dx:GridViewDataDateColumn FieldName="ShippedDate" Caption="Date of delivery" HeaderStyle-BackColor="Wheat" /> <dx:GridViewDataDateColumn FieldName="RequiredDate" Caption="Expiration date of delivery" HeaderStyle-BackColor="Wheat" Settings-AllowAutoFilter="False" /> </Columns> <Settings ShowFilterRow="true" /> </dx:ASPxGridView> <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString %>" ProviderName="<%$ ConnectionStrings:ConnectionString.ProviderName %>" SelectCommand="SELECT [ShipName], [ProductName], [ShippedDate], [RequiredDate] FROM [Invoices]" /> </div> </form> </body> </html>
Default.aspx.cs(vb)
C#
using DevExpress.Data.Filtering; using DevExpress.Web; using System; public partial class _Default : System.Web.UI.Page { const string SpecialFilterColumnFieldName = "ShippedDate", OtherFilterColumnFieldName = "RequiredDate"; protected void Page_Init(object sender, EventArgs e) { CriteriaOperator.RegisterCustomFunction(new MyCustomFunctionOperator()); } protected void Grid_ProcessColumnAutoFilter(object sender, DevExpress.Web.ASPxGridViewAutoFilterEventArgs e) { var grid = (ASPxGridView)sender; if(e.Column.FieldName == SpecialFilterColumnFieldName && e.Kind == GridViewAutoFilterEventKind.CreateCriteria) { grid.FilterExpression = UpdateGridFilterExpression(grid, e); e.Criteria = null; } } protected string UpdateGridFilterExpression(ASPxGridView grid, ASPxGridViewAutoFilterEventArgs e) { var gridCriteria = CriteriaOperator.Parse(grid.FilterExpression); gridCriteria = CriteriaVisitor.RemoveCustomFunction(gridCriteria, e.Column.FieldName); var customCriteria = new FunctionOperator(FunctionOperatorType.Custom, MyCustomFunctionOperator.Name, e.Value, new OperandProperty(e.Column.FieldName), new OperandProperty(OtherFilterColumnFieldName)); if(ReferenceEquals(gridCriteria, null) && ReferenceEquals(customCriteria, null)) return string.Empty; return GroupOperator.And(gridCriteria, customCriteria).ToString(); } protected void Grid_AutoFilterCellEditorCreate(object sender, ASPxGridViewEditorCreateEventArgs e) { if(e.Column.FieldName == SpecialFilterColumnFieldName) e.EditorProperties = new ComboBoxProperties(); } protected void Grid_AutoFilterCellEditorInitialize(object sender, ASPxGridViewEditorEventArgs e) { var grid = (ASPxGridView)sender; if(e.Column.FieldName == SpecialFilterColumnFieldName) { InitializeFilterCombobox((ASPxComboBox)e.Editor); var gridCriteria = CriteriaOperator.Parse(grid.FilterExpression); e.Editor.Value = CriteriaVisitor.GetCustomFunctionOperatorValue(gridCriteria, e.Column.FieldName); } } protected void InitializeFilterCombobox(ASPxComboBox editor) { editor.ValueType = typeof(string); editor.Items.Add("Delivered in time", "OK"); editor.Items.Add("Delivered with delay", "NOTOK"); editor.Items.Add("Delivery lost", "ISSUE"); } }

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.