This is a migrated thread and some comments may be shown as answers.

Custom Filter (AND / OR / ...)

6 Answers 49 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Steven
Top achievements
Rank 1
Steven asked on 30 Jun 2011, 08:57 AM
Goord morning,

I am using the CustomFilterDescriptor in your "RadControls for Silverlight Demos" and I would like to improve its functionalities.

I would like to this :

- "A + B" : Filtering data that contain A AND B
- "A || B" : Filterting data that contain A OR B
- "MyColum : A ": Filtering that on "MyColumn" which contains A
...

I could not find in where I can customize the linq expression.

Thank you for your help,
S

6 Answers, 1 is accepted

Sort by
0
Dimitrina
Telerik team
answered on 30 Jun 2011, 04:19 PM
Hi Steven,

 In this help article you may find additional information about the functionality of CustomFilterDescriptor. There is an information on how to filter with 'AND', 'OR' or 'Contains'.

I am not sure that I completely understand what you mean by: "I could not find in where I can customize the linq expression". May you please clarify how you would like to customize it?

Best wishes,
Didie
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Steven
Top achievements
Rank 1
answered on 20 Jul 2011, 01:04 PM
Hi,

I have an issue with the FilterOperator.DoesNotContain. It does not Filter correctly...

Sample :

MyDataSource :

item1
item2
item3

1. MyFirstFilterSampleValue : =item1 ( => FilterOperator.Contains : must return item1 only)
Return : item1 (it works)

1. MySecondFilterSampleValue : !=item1 ( => FilterOperator.DoesNotContains: must return item2 & item3 only)
Return : item1, item2, item3 (it does nott work)

Here is my CustomFilterDescriptor :

public class CustomFilterDescriptor : FilterDescriptorBase
    {
        private readonly CompositeFilterDescriptor compositeFilterDesriptor;
        private static readonly ConstantExpression TrueExpression = System.Linq.Expressions.Expression.Constant(true);
        IEnumerable<GridViewDataColumn> columns;
        private string filterValue;
 
        public CustomFilterDescriptor(IEnumerable<GridViewDataColumn> columns)
        {
            this.columns = columns;
            this.compositeFilterDesriptor = new CompositeFilterDescriptor();
            this.compositeFilterDesriptor.LogicalOperator = FilterCompositionLogicalOperator.Or;
 
            foreach (GridViewDataColumn column in columns)
            {
                this.compositeFilterDesriptor.FilterDescriptors.Add(this.CreateFilterForColumn(column));
            }
        }
 
        public string FilterValue
        {
            get
            {
                return this.filterValue;
            }
            set
            {
                if (this.filterValue != value)
                {
                    this.filterValue = value;
                    this.UpdateCompositeFilterValues();
                    this.OnPropertyChanged("FilterValue");
                }
            }
        }
 
        protected override System.Linq.Expressions.Expression CreateFilterExpression(ParameterExpression parameterExpression)
        {
            if (string.IsNullOrEmpty(this.FilterValue))
            {
                return TrueExpression;
            }
            try
            {
                return this.compositeFilterDesriptor.CreateFilterExpression(parameterExpression);
            }
            catch
            {
            }
 
            return TrueExpression;
        }
 
        private IFilterDescriptor CreateFilterForColumn(GridViewDataColumn column)
        {
            FilterOperator filterOperator = GetFilterOperatorForType(column.DataType);
            FilterDescriptor descriptor = new FilterDescriptor(column.UniqueName, filterOperator, this.filterValue);
            descriptor.MemberType = column.DataType;
 
            return descriptor;
        }
 
        private FilterOperator GetFilterOperatorForType(Type dataType)
        {
            FilterOperator filterOperator = FilterOperator.Contains;
 
            if (!String.IsNullOrEmpty(filterValue))
            {
                if (filterValue.StartsWith("!="))
                    return FilterOperator.IsNotEqualTo;
                if (filterValue.StartsWith("!"))
                    return FilterOperator.DoesNotContain;
                if (filterValue.StartsWith("="))
                    return FilterOperator.IsEqualTo;
                if (filterValue.StartsWith(">"))
                    return FilterOperator.IsGreaterThan;
            }
 
            return dataType == typeof(string) ? FilterOperator.Contains : FilterOperator.IsEqualTo;
        }
 
        private void UpdateCompositeFilterValues()
        {
            if (!String.IsNullOrEmpty(this.FilterValue))
            {
                this.compositeFilterDesriptor.FilterDescriptors.Clear();
 
                foreach (GridViewDataColumn column in columns)
                {
                    this.compositeFilterDesriptor.FilterDescriptors.Add(this.CreateFilterForColumn(column));
                }
 
                foreach (FilterDescriptor descriptor in this.compositeFilterDesriptor.FilterDescriptors)
                {
                    object convertedValue = DefaultValue(descriptor.MemberType);
 
                    try
                    {
                        if (descriptor.Value == null)
                            descriptor.Value = FilterDescriptor.UnsetValue;
                        if (descriptor.MemberType == null)
                            descriptor.MemberType = typeof(object);
 
                        if (descriptor.Operator== FilterOperator.IsNotEqualTo)
                            convertedValue = Convert.ChangeType(this.FilterValue.Remove(0, 2), descriptor.MemberType, CultureInfo.CurrentCulture);
                        else if (descriptor.Operator != FilterOperator.Contains || descriptor.Operator != FilterOperator.IsEqualTo)
                            convertedValue = Convert.ChangeType(this.FilterValue.Remove(0,1), descriptor.MemberType, CultureInfo.CurrentCulture);
                        else
                            convertedValue = Convert.ChangeType(this.FilterValue, descriptor.MemberType, CultureInfo.CurrentCulture);
                    }
                    catch
                    {
                    }
 
                    if (descriptor.MemberType.IsAssignableFrom(typeof(DateTime)))
                    {
                        DateTime date;
                        if (DateTime.TryParse(this.FilterValue, out date))
                        {
                            convertedValue = date;
                        }
 
                    }
 
                    descriptor.Value = convertedValue;
                }
            }
        }
 
        private static object DefaultValue(Type type)
        {
            if (type != null && type.IsValueType)
            {
                return Activator.CreateInstance(type);
            }
 
            return null;
        }
 
    }

Regards,
S
0
Rossen Hristov
Telerik team
answered on 20 Jul 2011, 01:36 PM
Hi Steven,

Let me explain what we do when it comes to filtering. 

Nothing that special.

We create a LINQ Expression based on the filter descriptors supplied. For the DoesNotContain filter operator we will create an expression that calls the String.Contains method and places "!" in front. So in fact, it is not us that filter that data but the .NET Framework. So, in pseudo code it will become something like this:

personCollection.Where(person => !person.LastName.Contains("John"))

It is not us that do the filtering -- it is the .NET Framework. So I can assure you that it is working correctly.

The DoesNotContain operator definitely works and you can see that in the default filtering UI of RadGridView on all of our on-line demos. Choose an arbitrary string column and test the DoesNotContain operator there. You will find out that it works correctly. Contains and DoesNotContain can be applied to strings only for the reasons I described above.

Most probably the problem comes from the fact that you have implemented your own custom filter descriptor, which I cannot take responsibility for. Please, check your implementation and whether it produces the correct LINQ expression. This lambda will be compiled and invoked to filter the data, so you can use your debugger to see what expression is your custom descriptor producing and where is the problem.

In case you think that you have found a bug with the default filtering of RadGridView, please send us a small sample project that does not involve custom descriptors and we will take a look at it.

Thank you for your understanding.

All the best,
Ross
the Telerik team

Register for the Q2 2011 What's New Webinar Week. Mark your calendar for the week starting July 18th and book your seat for a walk through of all the exciting stuff we will ship with the new release!

0
Rossen Hristov
Telerik team
answered on 20 Jul 2011, 01:47 PM
Hi Steven,

I think I know what the problem is. It is because of the OR operator when you use DoesNotContain. For Contains OR might be fine, but when you have DoesNotContain everything is inverted. Let me give you an example:

Person.FirstName.Contains("John") OR Person.LastName.Contains("John")

will return all people that are called John or Johnson, i.e. that have the string John somewhere in the name.

Now let us invert this:

Person.FirstName.DoesNotContain("John") OR Person.LastName.DoesNotContain("John")

will basically return all people because of the OR thing.

So everything works correctly, but your boolean logic is wrong.

You can see what expression is generated before it is returned from the method CreateFilterExpression.

See it with the debugger to see what is there and why.

I hope this helps.

Best wishes,
Ross
the Telerik team

Register for the Q2 2011 What's New Webinar Week. Mark your calendar for the week starting July 18th and book your seat for a walk through of all the exciting stuff we will ship with the new release!

0
Steven
Top achievements
Rank 1
answered on 20 Jul 2011, 02:10 PM
Thats it ! You're right !

+       [System.Linq.Expressions.LogicalBinaryExpression]   {(((((IIF((item != null), item.Name, null) ?? "").ToLower() != "NY ".ToLower()) OrElse ((IIF((item != null), item.UserLogin, null) ?? "").ToLower() != "NY ".ToLower())) OrElse ((IIF((item != null), item.Group, null) ?? "").ToLower() != "NY ".ToLower())) OrElse (Convert(item) != Convert("NY ")))}    System.Linq.Expressions.LogicalBinaryExpression

I need to replace the OrElse by And... but I am not allowed to access CreateFilterExpression.

If I create my own CreateFilterExpression method and return and Expression should it work?

regards,
S
0
Rossen Hristov
Telerik team
answered on 20 Jul 2011, 02:24 PM
Hi Steven,

No, you should simply change the LogicalOperator of the CompositeFilterDescriptior from OR to AND and the resulting expression will be with AND's instead of with OR's.

See, you are doing this yourself in the beginning:

this.compositeFilterDesriptor.LogicalOperator = FilterCompositionLogicalOperator.Or;

When the user chooses DoesNotContain, you can change the operator to FilterCompositionLogicalOperator.And; and the resulting LINQ expression will be with AND's.

I hope this helps.

Kind regards,
Ross
the Telerik team

Register for the Q2 2011 What's New Webinar Week. Mark your calendar for the week starting July 18th and book your seat for a walk through of all the exciting stuff we will ship with the new release!

Tags
GridView
Asked by
Steven
Top achievements
Rank 1
Answers by
Dimitrina
Telerik team
Steven
Top achievements
Rank 1
Rossen Hristov
Telerik team
Share this question
or