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

Filter not working on GridViewDataColumn

15 Answers 660 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Aaron C
Top achievements
Rank 1
Aaron C asked on 06 Apr 2011, 10:59 PM
Hello, I have a RadGridView that uses filtering, and it's working on all columns except for one.  The difference is in the DataMemberBinding.  The columns that work use a binding path to bind to a property of the object.  For example:

DataMemberBinding="{Binding FileExtension}"


The one that doesn't work binds to the object itself and uses a value converter:

DataMemberBinding="{Binding Converter={StaticResource FilePathConverterForSearch}}"

Sorting works based on the property I have set in SortMemberPath, but filtering does not.  How can I get filtering to work on this column? 

Thanks,
Aaron

15 Answers, 1 is accepted

Sort by
0
Rossen Hristov
Telerik team
answered on 07 Apr 2011, 08:58 AM
Hi Aaron C,

Can you try to set the DataType of this column and see whether filtering will start working. The column needs to know the type and when there is a converter the type is "lost", i.e. the converter returns an object which can be anything, but I am sure that in your case it is always of the same type. Thus you should specify this type as the DataType of the column.

In case this does not help, can you please prepare a very small dummy project that mimics your original setup and send it to us. We will examine and debug it immediately to see what is the problem. You will have to open a separate support ticket in order to attach the project.

I hope this helps. We are looking forward to hearing from you.

All the best,
Ross
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
Aaron C
Top achievements
Rank 1
answered on 07 Apr 2011, 03:28 PM
Thanks for the quick reply Ross, any suggestions on the exact syntax for doing this with a custom object type?  The object I am binding to is a FileModelItem, and from what I've been reading I should be able to set the DataType like this:

DataType="FileModelItem"

This throws XAML parse errors, I also tried adding the xml namespace for the class and setting the datatype using that:

xmlns:Schemas="clr-namespace:MyApp.Models;assembly=MyApp"
  
...
  
DataType="Schemas:FileModelItem"
  
or
  
DataType="{Schemas:FileModelItem}

and every variation of those that  I could think of.  The only thing that does not throw a XAML parse error is binding the DataType to a ValueConverter and returning the type from the value converter.  This however still does not get filtering to work. 
0
Rossen Hristov
Telerik team
answered on 07 Apr 2011, 04:08 PM
Hi Aaron C,

I was not aware that your type was complex. Filtering will not work on a complex type unless you do several things. 

Since we perform filtering by using LINQ (i.e. Where), in order to filter complex types, you will need to do several things.

The only possible way to enable filtering on such a complex type would be to implement the IComparable and IEquatable interfaces. Additionally, the class should have its Equals and GetHashCode methods overriden. You must have GetHashCode, since it appears that the Distinct LINQ Extension method uses it. The class should also override the "==" and "!=" operators.

If all of these conditions are met, then the data engine should be able to compare items of this type and thus perform filtering on a list of such objects.

In case you are not happy with the stock filtering control, which is designed for simple types like strings, dates, numbers, etc. you can always develop your very own filtering control like I have described in my blog post.

If you don't want to do all of this, you can create a new string property on your business object that will somehow return a string representation of this FileModeItem. You will then show this new string column and you will have normal string filtering and you will not have to do anything additional. Simply hide the complex type column and show the string one.

Still, if you decide to stick to the complex type, you will have to set the column's DataType. Silverlight 4 will not allow you to set it like you have tried in XAML (let's hope SL 5 will...). You have to assign the DataType either either in code-behind or expose this particular type as a static resource and then data bind to it, if you really really want to specify the DataType in XAML.

I hope this helps.

Kind regards,
Ross
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
Viki
Top achievements
Rank 1
answered on 14 Feb 2012, 11:18 AM
Hi,

I have 2 columns (GridViewDataColumn) to be filterable, the columns are constructed on the run time, the data of this columns is binded, the Data Type of them is 'String', so I set it as follows:
column.DataType = typeof(string);

I do see the Filter sign on them and the Filter window is openned, but with 'Error on Page' in the left bottom corner of the application and the using of the filter is impossible.The error is: 'At least one object must implement IComparable', but 'String' already implements IComparable... So I don't know what I'm missing

Thanks,
Viki
0
Rossen Hristov
Telerik team
answered on 14 Feb 2012, 11:26 AM
Hello,

If you send us a sample project that demonstrates this, we will debug it. We need something that we can run and debug in order to help you.

Greetings,
Ross
the Telerik team
Sharpen your .NET Ninja skills! Attend Q1 webinar week and get a chance to win a license! Book your seat now >>
0
Viki
Top achievements
Rank 1
answered on 14 Feb 2012, 12:25 PM
Hi, thanks for the quick reply, I send you the relevants code pieces, hopefully it will be enough:
Xaml:
<telerikGrid:RadGridView x:Name="gridManagerReportResult" Grid.Row="3" Grid.Column="1" RowIndicatorVisibility="Collapsed"
                                 ScrollMode="RealTime" AutoGenerateColumns="False" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
                                 AutoExpandGroups="True" telerikControl:StyleManager.Theme="{StaticResource RosterTheme}"
                                 ElementExporting="gridManagerReportResult_ElementExporting">
            <telerikGrid:RadGridView.Columns>
                <telerikGrid:GridViewDataColumn Header="Data Type" UniqueName="DataType" DataMemberBinding="{Binding Data, Converter={StaticResource ValueConverter}, ConverterParameter=Name}" IsReadOnly="True"/>
            </telerikGrid:RadGridView.Columns>
        </telerikGrid:RadGridView>

C#:
private void InitializeData()
        {
            try
            {
                // Build the dynamic Days columns
                BuildDaysColumns();
  
                gridManagerReportResult.ItemsSource = m_DataTable.Table.EmployeesData;
  
                // Enabling the column's Filter on the 'Data Type' column
                var column = this.gridManagerReportResult.Columns["DataType"] as GridViewBoundColumnBase;
                if (column != null)
                {
                    column.DataType = typeof(string);
                }
            }
            catch (Exception ex)
            {
                  
            }
        }
  
  
        private void BuildDaysColumns()
        {
            if (m_DataTable.Table != null && m_DataTable.Table.ReportTime.Duration.Days > 0)
            {
                int iDaysCount = m_DataTable.Table.ReportTime.Duration.Days;
                for (int iDayIndex = 0; iDayIndex < iDaysCount; iDayIndex++)
                {
                    GridViewDataColumn column = new GridViewDataColumn();
  
                    // Set the Binding to SingleEmployeeReport => RowObject.Data
                    Binding binding = new Binding("Data");
                    binding.Mode = BindingMode.OneWay;
                    // Set the Converter
                    binding.Converter = new PS_DayColumnConverter();
                    binding.ConverterParameter = iDayIndex;
  
                    column.DataMemberBinding = binding;
                    column.Header = m_DataTable.Table.ReportTime.Start.AddDays(iDayIndex).ToString("ddd, d/MM/yy");
                    column.IsReadOnly = true;
                    column.Width = 130;
                    // Enabling the column's Filter
                    column.DataType = typeof(string);
  
                    gridManagerReportResult.Columns.Add(column);
                }
            }
        }
  
  
public class PS_DayColumnConverter : IValueConverter
    {
        #region IValueConverter Members
  
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (parameter == null) return null;
  
            EmployeeDataType data = value as EmployeeDataType;
  
            // The 'parameter' is 'Name' for Data Type name
            if (parameter.ToString().Equals("Name"))
            {
                return data.DataName; //DataName is 'String' 
            }
  
            // If 'parameter' isn't 'Name' it is column index
            int iColumnIndex = (int)parameter;
  
            List<String> lstDaysData = data.DataValues;
  
            if (iColumnIndex >= lstDaysData.Count)
            {
                return null;
            }
            return lstDaysData[iColumnIndex]; //lstDaysData is List<String>
        }
  
  
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return null;
        }
  
        #endregion
    }
0
Rossen Hristov
Telerik team
answered on 14 Feb 2012, 12:47 PM
Hi,

Unfortunately, I am not able build and to run the code snippets that you have provided. I can only make wild guesses by looking at that code.

What I can see is that you are binding the column to a EmployeeDataType and then you are telling it that its DataType is a string, which is obviously wrong. The EmployeeDataType type is not a string.

Filtering, Sorting and Grouping are always performed on the raw data values -- they don't take IValueConverters in mind, since IValueConverters are for display purposes only and they do not play any part in the data engine. This is how RadGridView is designed and works.

So the bottom-line is that if your column is bound to a EmployeeDataType, you can's simply lie to it and tell it that its DataType is a string when it obviously is not.

But then again, I don't have anything that I can run and debug so this is just my wild guess. 

Greetings,

Ross
the Telerik team
Sharpen your .NET Ninja skills! Attend Q1 webinar week and get a chance to win a license! Book your seat now >>
0
Viki
Top achievements
Rank 1
answered on 14 Feb 2012, 01:13 PM
So, from what I understand, I get the same answer, as Aaron C.:"The only possible way to enable filtering on such a complex type would be to implement the IComparable and IEquatable interfaces. Additionally, the class should have its Equals and GetHashCode methods overriden. You must have GetHashCode, since it appears that the Distinct LINQ Extension method uses it. The class should also override the "==" and "!=" operators."

0
Rossen Hristov
Telerik team
answered on 14 Feb 2012, 01:33 PM
Hello,

Yes. We can not compare objects unless they are comparable in some way.

However, you no longer need to override the '==' and '!=' operators since we now build a LINQ expression that uses an Object.Equals method call instead of the equality and inequality operators.

But in case you want your filtering control to show the IsGreaterThan, IsLessThan, IsGreaterThanOrEqual and IsLessThanOrEqual options you would have to override the respective operators on your custom class: >, <, >=, <=.

I hope this helps.

All the best,
Ross
the Telerik team
Sharpen your .NET Ninja skills! Attend Q1 webinar week and get a chance to win a license! Book your seat now >>
0
Viki
Top achievements
Rank 1
answered on 15 Feb 2012, 02:05 PM
Hi, me again :)

I simplified the code, so now the columns that are created on the run time, their content is bound to data of List<String> type (where column index (date) is an index in this List, so each column is of String type).
So do I have now simplier way (than to implement IComparable and IEquantable interfaces and override Equals and GetHashCode methods) to get the column to be filterable?

Here is the relevant code:
private void BuildDaysColumns()
        {
            if (m_DataTable.Table != null && m_DataTable.Table.ReportTime.Duration.Days > 0)
            {
                int iDaysCount = m_DataTable.Table.ReportTime.Duration.Days;
                for (int iDayIndex = 0; iDayIndex < iDaysCount; iDayIndex++)
                {
                    GridViewDataColumn column = new GridViewDataColumn();
  
                    // Set the Binding to SingleEmployeeReport => RowObject.Data
                    Binding binding = new Binding("DataValues");
                    binding.Mode = BindingMode.OneWay;
                    // Set the Converter
                    binding.Converter = new PS_DayColumnConverter();
                    binding.ConverterParameter = iDayIndex;
  
                    column.DataMemberBinding = binding;
                    column.Header = m_DataTable.Table.ReportTime.Start.AddDays(iDayIndex).ToString("ddd, d/MM/yy");
                    column.IsReadOnly = true;
                    column.Width = 130;
                    column.DataType = typeof(List<string>);// ????????
  
                    gridManagerReportResult.Columns.Add(column);
                }
            }
        }
  
  
public class PS_DayColumnConverter : IValueConverter
    {
        #region IValueConverter Members
  
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (parameter == null) return null;
            int iColumnIndex = (int)parameter;
  
            List<String> lstDaysData = value as List<string>;
  
            if (iColumnIndex >= lstDaysData.Count)
            {
                return null;
            }
            return lstDaysData[iColumnIndex];
        }
  
  
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return null;
        }
  
        #endregion
    }


Thanks,
Viki
0
Rossen Hristov
Telerik team
answered on 15 Feb 2012, 02:27 PM
Hi,

No. If you bind a column to show a property which is a List<string> you will not get any filtering at all.

How do you compare two List<string> instances? You can't.

List<string> list1 = <<something>>;
List<string> list2 = <<something else>>;

What does list1 < list2 return? What does list1 > list2 return? It will not even compile.

This will not work.

Greetings,
Ross
the Telerik team
Sharpen your .NET Ninja skills! Attend Q1 webinar week and get a chance to win a license! Book your seat now >>
0
Rossen Hristov
Telerik team
answered on 15 Feb 2012, 02:34 PM
Hello,

Let me try to explain this once more.

Filtering, Sorting and Grouping are always performed on the raw data values -- they don't take IValueConverters in mind, since IValueConverters are for display purposes only and they do not play any part in the data engine

So if your column is data-bound to something of type X, this X has to meet the filtering requirements in order for filtering to work. Which List<string> does not, obviously.

Please, forget what you see in the grid cells after the IValueConverter has been applied. The IValueConverter is used for display purposes only.

Data operations are performed on the raw values that the column is bound to.

And List<string> obviously can not be filtered, so there is absolutely no point in binding your column to a list of strings.

I hope that this makes sense.

Greetings,
Ross
the Telerik team
Sharpen your .NET Ninja skills! Attend Q1 webinar week and get a chance to win a license! Book your seat now >>
0
Viki
Top achievements
Rank 1
answered on 16 Feb 2012, 07:50 AM
Hi, Ross

Thank you for your detailed and well argued response :)

The columns that are bound to the List<String> data are constructed on the run time and their amount is unknown before it, so I don't see another option of their data binding, but to List.

So, thanks again!
Viki
0
Alex
Top achievements
Rank 1
answered on 18 Nov 2014, 09:41 AM
Hi guys, I believe this info:
"The only possible way to enable filtering on such a complex type would be to implement the IComparable and IEquatable interfaces. Additionally, the class should have its Equals and GetHashCode methods overriden. You must have GetHashCode, since it appears that the Distinct LINQ Extension method uses it. The class should also override the "==" and "!=" operators."

in yours documentation and for WPF also.

Any way I faced with similar issue in WPF project and a few hours to find solution. My complex type satisfies all requirements(implement the IComparable and IEquatable and etc). But it doesn't help as it needs magic in xaml. As result I got working sorting and almost filtering but got another issue. 
I have column that you can see below(I wonder how to continue message after pasting code block, probably IE issue but still one more issue). Applying FilterMemberPath property kills filtering and popup shows empty list. Without this property Filter popup just calls ToString method. Also I tried to use FilterMemberPath="Name" grid use member of the parent object. So do I have another solutions than overriding ToString in my complex type and rewriting filter popup? 
<telerik:GridViewDataColumn DataMemberBinding="{Binding IndexType}"
                   FilterMemberPath="IndexType.Name"
                   Header="{x:Static localization:Resources.Type}">
          <telerik:GridViewDataColumn.CellTemplate>
                 <DataTemplate>
                       <TextBlock Text="{Binding IndexType.Name}" />
                 </DataTemplate>
          </telerik:GridViewDataColumn.CellTemplate>
 </telerik:GridViewDataColumn>
0
Dimitrina
Telerik team
answered on 18 Nov 2014, 04:03 PM
Hi Alex,

I will try to elaborate more on how the filtering actually works. It is a data operation which means it is done by building and executing a LINQ query appending proper Where clause over the source collection. 

For example:
var result = collection.Where(item => item.Property == "Something");


The reason for not working should be that our data engine cannot build a valid LINQ query based on the specified binding. So, if you can build such a LINQ query appending Where clause based on the DataMemberBinding set for a column, then RadGridView should also be able to filter the respective column. Otherwise, this will not be possible.

If you can build a valid LINQ query and RadGridView still does not respond accordingly, then may I ask you to isolate the case in a demo project which we can check locally? You can open a new support ticket and attach it there.

Regards,
Dimitrina
Telerik
 

Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

 
Tags
GridView
Asked by
Aaron C
Top achievements
Rank 1
Answers by
Rossen Hristov
Telerik team
Aaron C
Top achievements
Rank 1
Viki
Top achievements
Rank 1
Alex
Top achievements
Rank 1
Dimitrina
Telerik team
Share this question
or