Search code examples
devexpresscriteriaxtragridautofilterdevexpress-windows-ui

XtraGrid AutoFilterRow custom range filtering


I'm trying to improve the AutoFilterRow functionality for one of my columns. The column will always consist of a string that represents a range of values like this: "num1 - num2". I would like to allow end users to type a value into the cell in the AutoFilterRow and in this particular column and the rows whose sections have a range that includes the number they typed. For instance, if I had 3 rows and each of their section attributes were the following: "1 - 4", "1 - 6", and "4 - 6", and a user types "3" into the AutoFilterRow cell for this column, I would expect the rows containing "1 - 4" and "1 - 6".

I have already overwritten the CreateAutoFilterCriterion in MyGridView to allow for additional operators as suggested in several examples found on this site:

protected override CriteriaOperator CreateAutoFilterCriterion(GridColumn column, AutoFilterCondition condition, object _value, string strVal)
{
    if ((column.ColumnType == typeof(double) || column.ColumnType == typeof(float) || column.ColumnType == typeof(int)) && strVal.Length > 0)
    {
        BinaryOperatorType type = BinaryOperatorType.Equal;
        string operand = string.Empty;
        if (strVal.Length > 1)
        {
            operand = strVal.Substring(0, 2);
            if (operand.Equals(">="))
                type = BinaryOperatorType.GreaterOrEqual;
            else if (operand.Equals("<="))
                type = BinaryOperatorType.LessOrEqual;
            else if (operand.Equals("<>"))
                type = BinaryOperatorType.NotEqual;
        }
        if (type == BinaryOperatorType.Equal)
        {
            operand = strVal.Substring(0, 1);
            if (operand.Equals(">"))
                type = BinaryOperatorType.Greater;
            else if (operand.Equals("<"))
                type = BinaryOperatorType.Less;
            else if (operand.Equals("!") || operand.Equals("~"))
                type = BinaryOperatorType.NotEqual;
        }
        if (type != BinaryOperatorType.Equal)
        {
            string val = strVal.Replace(operand, string.Empty);
            try
            {
                if (!val.IsEmpty())
                {
                    if (column.ColumnType == typeof(double))
                    {
                        var num = Double.Parse(val, NumberStyles.Number, column.RealColumnEdit.EditFormat.Format);
                        return new BinaryOperator(column.FieldName, num, type);
                    }
                    if (column.ColumnType == typeof(float))
                    {
                        var num = float.Parse(val, NumberStyles.Number, column.RealColumnEdit.EditFormat.Format);
                        return new BinaryOperator(column.FieldName, num, type);
                    }
                    else
                    {
                        var num = int.Parse(val, NumberStyles.Number, column.RealColumnEdit.EditFormat.Format);
                        return new BinaryOperator(column.FieldName, num, type);
                    }
                }
                // DateTime example:
                // DateTime dt = DateTime.ParseExact(val, "d", column.RealColumnEdit.EditFormat.Format);
                // return new BinaryOperator(column.FieldName, dt, type);
            }
            catch
            {
                return null;
            }
        }
    }
    //
    // HERE IS WHERE I WANT TO ADD THE FUNCTIONALITY I'M SPEAKING OF
    //
    else if (column.FieldName == "SectionDisplayUnits")
    {
        try
        {
            if (!strVal.IsEmpty())
            {
                
            }
        }
        catch
        {
            return null;
        }
    }
    return base.CreateAutoFilterCriterion(column, condition, _value, strVal);
}

How would I go about doing that? I figure I want to split each string with a call to Split(...) like this: cellString.Split(' - '). Then I would parse each string returned from the call to Split(...) into a number so that I could use inequality operators. But I'm just not sure how to go about doing this. Can I get some help? Thanks!

Update:

Please take a look here for a more in-depth discussion on this matter with myself and a knowledgeable DevExpress representative. I received a lot of help and I wanted to share this knowledge with whoever needs similar assistance. Here is the link.


Solution

  • Using C#, you would split the value into two parts, convert them to the number, and compare the value entered by the user with both values to ensure that it is greater or equal the first part and less or equal the second part.

    In Criteria Language, the same functionality can be created using Function Operators. However, the expression will be a bit complex. Please try the following. It will work only if the format of values in the SectionDisplayUnits column is fixed, and the value always consists of two numbers delimited by "-".

    string rangeDelimiter = "-";
    return CriteriaOperator.Parse("toint(trim(substring(SectionDisplayUnits, 0, charindex(?, SectionDisplayUnits)))) <= ? && toint(trim(substring(SectionDisplayUnits, charindex(?, SectionDisplayUnits) + 1, len(SectionDisplayUnits) - charIndex(?, SectionDisplayUnits) - 1))) >= ?", rangeDelimiter, _value, rangeDelimiter, rangeDelimiter, _value);