This example demonstrates how to use a CriteriaPatchBase class descendant to apply a custom function 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
- CriteriaPatcherBase.cs (VB: CriteriaPatcherBase.vb)
- CriteriaVisitor.cs (VB: CriteriaVisitor.vb)
- MyCustomFunctionOperator.cs (VB: MyCustomFunctionOperator.vb)
- Default.aspx (VB: Default.aspx)
- Default.aspx.cs (VB: Default.aspx.vb)
Documentation
Example Code
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
}
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;
}
}
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); }
}
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>
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");
}
}