Default filtering for a column with semicolon separtated values

12 posts, 0 answers
  1. Trent Jones
    Trent Jones avatar
    49 posts
    Member since:
    Aug 2009

    Posted 20 Jun 2011 Link to this post

    Is it possible to override the list with checkboxes in the default filter box to show unique values instead of the semicolons etc?

    In the screenshot attached, lets say that i have Jones, Trent as a value in that column on multiple rows.  I want the "selection list" to only show the values (without semicolon) and only show Jones, Trent once.

    Thanks.
  2. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 21 Jun 2011 Link to this post

    Hello Trent Jones,

     It is not a good approach to override the list with checkboxes in the default filter box as the filtering will not find any results on this new values that you have (unless you have cells with exact the same value). Filtering is using "==" to compare the values from the check boxes with the values in the cells and it will filter only on exact match.

    Filtering in this way may have many unwanted consequences because the filtering mechanism and UI is not supposed to work that way. 

    What is the way to go is to use the standard way of filtering or create a custom filtering control which will be able to handle this specific case. There you may use a ColumnFilterDescriptor with operator Contains for the string values in the check boxes.

    I hope that this helps. 

    Regards,
    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
  3. DevCraft banner
  4. Trent Jones
    Trent Jones avatar
    49 posts
    Member since:
    Aug 2009

    Posted 21 Jun 2011 Link to this post

    I've actually now acheived this in two ways.

    1. used DistinctValuesLoading to change the Distinct values list for a particular column.
    2. used Attached behavior to change "IsEqualTo" to "Contains"
    3. clicking apply filter does the work.

    My last issue is how to change the UI so that when you click a distinct value checkbox (which does the filtering on the fly) that it changes the grid like clicking "apply filter" does.
  5. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 21 Jun 2011 Link to this post

    Hi Trent Jones,

    Clicking on a distinct value will automatically filter the grid immediately and this is the default behavior of our grid so I am not sure what you are doing. You can see this behavior on all of our online examples.

    Also, how did you manage to alter the underlying FilterDescriptor that sits behind the distinct value and change its FilterOperator from IsEqualTo to Contains? Could you please elaborate? Are you using your own custom filtering control or the stock one?

    I am looking forward to hearing from you.

    Greetings,
    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. Trent Jones
    Trent Jones avatar
    49 posts
    Member since:
    Aug 2009

    Posted 21 Jun 2011 Link to this post

    1. Override the distinct values

    void radGridView1_DistinctValuesLoading(object sender, Telerik.Windows.Controls.GridView.GridViewDistinctValuesLoadingEventArgs e)
            {
                if (e.Column.CanFilter() == true && (string)e.Column.Header == "Matters")
                {
                    e.ItemsSource = _items.SelectMany(item => item.Matters.Select(matt => matt.Name)).Distinct();// radGridView1.GetDistinctValues(e.Column, true, radGridView1.Items.Count);
                }
                 
            }

    Attached Behaviour

    public class DistinctValuesUsingContainsBehavior : Behavior<GridViewBoundColumnBase>
        {
            FilteringControl customFilteringControl;
            CheckBox selectAllDistinct;
            Button applyFilterButton;
            Button clearFilterButton;
            System.Windows.Controls.ListBox distinctValuesList;
     
            protected override void OnAttached()
            {
                this.customFilteringControl = new FilteringControl();
                this.customFilteringControl.Loaded += this.OnFilteringControlLoaded;
                this.AssociatedObject.FilteringControl = customFilteringControl;
            }
     
            void OnFilteringControlLoaded(object sender, RoutedEventArgs e)
            {
                // Find controls and associate events
                this.applyFilterButton = this.customFilteringControl
                    .ChildrenOfType<Button>()
                    .Where(b => b.Name == "PART_ApplyFilterButton")
                    .FirstOrDefault();
     
                if (this.applyFilterButton != null)
                {
                    this.applyFilterButton.Click += this.OnApplyFilter;
                }
     
                this.clearFilterButton = this.customFilteringControl
                    .ChildrenOfType<Button>()
                    .Where(b => b.Name == "PART_ClearFilterButton")
                    .FirstOrDefault();
     
                if (this.clearFilterButton != null)
                {
                    this.clearFilterButton.Click += this.OnClearFilter;
                }
     
                // Are distint filters permitted on this column
                if (this.customFilteringControl.DistinctFiltersVisibility == Visibility.Visible)
                {
                    this.selectAllDistinct = this.customFilteringControl
                        .ChildrenOfType<CheckBox>()
                        .Where(l => l.Name == "PART_SelectAllCheckBox")
                        .FirstOrDefault();
     
                    this.selectAllDistinct.Checked += new RoutedEventHandler(OnSelectAllChecked);
                    this.selectAllDistinct.Unchecked += new RoutedEventHandler(OnSelectAllUnchecked);
     
                    this.distinctValuesList = this.customFilteringControl
                        .ChildrenOfType<System.Windows.Controls.ListBox>()
                        .Where(l => l.Name == "PART_DistinctValuesList")
                        .FirstOrDefault();
                }
     
                //this.applyFilterButton = this.customControl
                //    .ChildrenOfType<Button>()
                //    .Where(b => b.Name == "PART_ApplyFilterButton")
                //    .FirstOrDefault();
     
     
                ////PART_DistinctValuesList
                //this.distinctValuesList = this.customControl
                //    .ChildrenOfType<System.Windows.Controls.ListBox>()
                //    .Where(b => b.Name == "PART_DistinctValuesList")
                //    .FirstOrDefault();
                 
                ////FilteringViewModel m = newList.DataContext as FilteringViewModel;
     
                ////IEnumerable<Tuple<string[],bool>> data = m.DistinctValues.Select(dvm => new Tuple<string[],bool>(dvm.ConvertedValue.ToString().Split(';').ToArray<string>(), dvm.IsActive) );
                 
                 
     
     
                //if (this.applyFilterButton != null)
                //{
                //    this.applyFilterButton.Click += this.OnApplyFilter;
                //}
            }
     
            void OnSelectAllChecked(object sender, RoutedEventArgs e)
            {
                SelectAll(true);
            }
     
            void OnSelectAllUnchecked(object sender, RoutedEventArgs e)
            {
                SelectAll(false);
            }
     
            private void SelectAll(bool check)
            {
                if (this.selectAllDistinct != null && this.distinctValuesList != null)
                {
                    // Check / uncheck items
                    var chks = this.distinctValuesList.ChildrenOfType<CheckBox>();
     
                    foreach (var chk in chks)
                    {
                        chk.IsChecked = check;
                    }
     
                    // Set view model property
                    ((FilteringViewModel)this.customFilteringControl.DataContext).SelectAll = check;
                }
            }
     
            public void OnApplyFilter(object sender, RoutedEventArgs e)
            {
                if (this.customFilteringControl.DistinctFiltersVisibility == Visibility.Visible && this.distinctValuesList != null)
                {
                    ColumnFilterDescriptor columnDescriptor;
                    bool addDesc = false;
     
                    var descriptor = this.AssociatedObject.DataControl.FilterDescriptors
                        .Where(desc => ((ColumnFilterDescriptor)desc).Column.GetDataMemberName() == this.AssociatedObject.GetDataMemberName())
                        .FirstOrDefault();
     
                    if (descriptor == null)
                    {
                        // Create new filter if we don't already have one
                        columnDescriptor = new ColumnFilterDescriptor((IDataFieldDescriptor)this.AssociatedObject.DataControl.Columns[this.AssociatedObject.DisplayIndex]);
                        addDesc = true;
                    }
                    else
                    {
                        // Clear distinct values filter from existing filter
                        columnDescriptor = (ColumnFilterDescriptor)descriptor;
                        //Expression
                        //columnDescriptor.DistinctFilter.FilterDescriptors[0].CreateFilterExpression()
                        columnDescriptor.DistinctFilter.DistinctValues.Clear();
                    }
     
                    var chks = this.distinctValuesList.ChildrenOfType<CheckBox>();
     
                     
     
                    foreach (var chk in chks)
                    {
                        if (chk.IsChecked.HasValue && chk.IsChecked.Value)
                        {
                            if (this.AssociatedObject.DataType == typeof(bool))
                            {
                                if (string.Compare(chk.Content.ToString().ToLower(), "true") == 0)
                                {
                                    columnDescriptor.DistinctFilter.DistinctValues.Add(true);
                                }
                                else
                                {
                                    columnDescriptor.DistinctFilter.DistinctValues.Add(false);
                                }
                            }
                            else
                            {
                                columnDescriptor.DistinctFilter.DistinctValues.Add(chk.Content);
                            }
                        }
                    }
                    foreach (FilterDescriptor x in columnDescriptor.DistinctFilter.FilterDescriptors)
                    {
                        x.Operator = FilterOperator.Contains;
                    }
     
                    if (addDesc && columnDescriptor.DistinctFilter.DistinctValues.Count > 0)
                    {
                        this.AssociatedObject.DataControl.FilterDescriptors.Add(columnDescriptor);
                    }
                }
     
                // And when clicked find the parent popup and close it.
                var popup = applyFilterButton.ParentOfType<System.Windows.Controls.Primitives.Popup>();
                if (popup != null)
                {
                    popup.IsOpen = false;
                }
            }
     
            void OnClearFilter(object sender, RoutedEventArgs e)
            {
                // And when clicked find the parent popup and close it.
                var popup = clearFilterButton.ParentOfType<System.Windows.Controls.Primitives.Popup>();
                if (popup != null)
                {
                    popup.IsOpen = false;
                }
            }
     
            protected override void OnDetaching()
            {
                if (this.applyFilterButton != null)
                {
                    this.applyFilterButton.Click -= this.OnApplyFilter;
                }
       
                if (this.clearFilterButton != null)
                {
                    this.clearFilterButton.Click -= this.OnClearFilter;
                }
       
                if (this.selectAllDistinct != null)
                {
                    this.selectAllDistinct.Checked -= this.OnSelectAllChecked;
                    this.selectAllDistinct.Unchecked -= this.OnSelectAllUnchecked;
                }
       
                this.customFilteringControl.Loaded -= this.OnFilteringControlLoaded;
            }
        }

    Using behaviour

    <telerik:GridViewDataColumn Header="Matters" DataMemberBinding="{Binding MatterNames}" ShowFieldFilters="False" ShowDistinctFilters="False">
                        <i:Interaction.Behaviors>
                            <my:DistinctValuesUsingContainsBehavior/>
                        </i:Interaction.Behaviors>
                    </telerik:GridViewDataColumn>

    MatterNames from view model:

    public string MatterNames
            {
                get {
                    return string.Join(";", _matters.Select(mat => mat.Name));
                }
            }

    Try it and you will see i still need to override the individual check boxes somehow.
  7. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 21 Jun 2011 Link to this post

    Hi Trent Jones,

    I am a little bit shocked by this code.

    You have taken our stock control and altered its built-in behaviour beyond recognition.

    You have managed to change almost everything.

    You are not supposed to interfere in its inner workings in this way.

    You can't possibly expect things to work in this case and I can no longer guarantee that they will work, since this is not our control any-more. The fact that something is public, does not mean that it should be tampered with. In this case we had to make the view model public since Silverlight will complain otherwise. This does not mean that you should cast the DataContext to our view model class and start changing stuff.

    The stock FilteringControl was designed to work in a certain way and interfering with its inner workings can render it useless. 

    I am afraid that I cannot support this "new" FilteringControl, since you have totally altered its built-in logic and this is no longer our FilteringControl.

    My suggestion is to create your very own FilteringControl from scratch and weave any kind of custom logic that you want. You will be in charge of everything -- the UI, the view model that sits behind and the filtering logic. The idea is simple -- you provide the UI that you want to the end user, you respond to user actions over this UI and based on these action you add, removed or modify a ColumnFilterDescriptor like described in my blog post. This will be much easier for you than trying to make something work in a way it was not really designed for.

    I hope this makes sense.

    Greetings,
    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
  8. Trent Jones
    Trent Jones avatar
    49 posts
    Member since:
    Aug 2009

    Posted 21 Jun 2011 Link to this post

    The stuff that was commented was just that, commented.  I agree and that didn't work anyway because there are no setters.

    However, this control, is exactly the same as the one mentioned here:
    http://blogs.telerik.com/blogs/posts/10-01-22/how_to_customize_radgridview_s_default_filtering_control_with_attached_behaviors_silverlight_amp_wpf.aspx

    with the addition of two things.  "close when clear filter" and "contains" rather than "IsEqualTo"

    The suggestion on the blog post is exactly what i was after.  I wanted just to change "IsEqualTo" to contains.  I don't care about the "close popup" on "fitler" or "Clear Filter". 

    Let me clean up the attached behavior to only do the "Contains" bit.

    Reality is i copy-pasted all of that from another forum entry on your site minus these lines:

    foreach (FilterDescriptor x in columnDescriptor.DistinctFilter.FilterDescriptors)
                    {
                        x.Operator = FilterOperator.Contains;
                    }

  9. Trent Jones
    Trent Jones avatar
    49 posts
    Member since:
    Aug 2009
  10. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 21 Jun 2011 Link to this post

    Hello Trent Jones,

    We can not support this kind of a custom solution taken from various blog and forum posts as a true genuine product. 

    Thank you for your understanding.

    My suggestion is to create your very own FilteringControl from scratch and weave any kind of custom logic that you want. You will be in charge of everything -- the UI, the view model that sits behind and the filtering logic. The idea is simple -- you provide the UI that you want to the end user, you respond to user actions over this UI and based on these action you add, removed or modify a ColumnFilterDescriptor like described in my blog post. This will be much easier for you than trying to make something work in a way it was not really designed for.

    Greetings,
    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
  11. Trent Jones
    Trent Jones avatar
    49 posts
    Member since:
    Aug 2009

    Posted 21 Jun 2011 Link to this post

    you were the one that recommended it.

    "Very often, however, you may be perfectly happy with the stock filtering control, but you wish you could modify and adapt it just a little bit to match your particular requirements. What should you do then?"

    http://blogs.telerik.com/blogs/posts/10-01-22/how_to_customize_radgridview_s_default_filtering_control_with_attached_behaviors_silverlight_amp_wpf.aspx

    I just want to change a small bit and still get Skinning, etc.

    Great you don't recommend it.  but you tell us how to do it.  therefore it should be supported.  I don't want to rewrite the entire control.

  12. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 21 Jun 2011 Link to this post

    Hi Trent Jones,

    I am not sure how to explain this. The approach you have undertaken is not possible. The stock filtering control cannot operate in the way you expect it to. It was designed with another behavior at mind, and the one you want to achieve is simply not possible with it. It was not designed to perform the kind of filtering you want. There is nothing we can do to change that, since your requirement is quite custom and our stock control can not handle it. I hope this makes sense. Thank you for your understanding.

    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
  13. Trent Jones
    Trent Jones avatar
    49 posts
    Member since:
    Aug 2009

    Posted 21 Jun 2011 Link to this post

    Maybe i wasn't clear, this actually works!  I used an attached behavior to modify one part of the control and apply it to a particular column.  Nothing changes in the UI.   That was the point of your article.  I gain consistency from UX across the filters.

    Yes, I can do a customfilter, which a had already done.  However i like this approach too as described by your own blog post.

Back to Top
DevCraft banner