Filter not working on GridViewDataColumn

16 posts, 0 answers
  1. Aaron C
    Aaron C avatar
    23 posts
    Member since:
    Sep 2009

    Posted 06 Apr 2011 Link to this post

    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

  2. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 07 Apr 2011 Link to this post

    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
  3. DevCraft banner
  4. Aaron C
    Aaron C avatar
    23 posts
    Member since:
    Sep 2009

    Posted 07 Apr 2011 Link to this post

    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. 
  5. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 07 Apr 2011 Link to this post

    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
  6. Viki
    Viki avatar
    20 posts
    Member since:
    Dec 2010

    Posted 14 Feb 2012 Link to this post

    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
  7. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 14 Feb 2012 Link to this post

    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 >>
  8. Viki
    Viki avatar
    20 posts
    Member since:
    Dec 2010

    Posted 14 Feb 2012 Link to this post

    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
        }
  9. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 14 Feb 2012 Link to this post

    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 >>
  10. Viki
    Viki avatar
    20 posts
    Member since:
    Dec 2010

    Posted 14 Feb 2012 Link to this post

    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."

  11. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 14 Feb 2012 Link to this post

    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 >>
  12. Viki
    Viki avatar
    20 posts
    Member since:
    Dec 2010

    Posted 15 Feb 2012 Link to this post

    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
  13. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 15 Feb 2012 Link to this post

    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 >>
  14. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 15 Feb 2012 Link to this post

    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 >>
  15. Viki
    Viki avatar
    20 posts
    Member since:
    Dec 2010

    Posted 16 Feb 2012 Link to this post

    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
  16. Alex
    Alex avatar
    19 posts
    Member since:
    Feb 2012

    Posted 18 Nov 2014 Link to this post

    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>
  17. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 18 Nov 2014 Link to this post

    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.

     
Back to Top
DevCraft banner