Problem with custom filter with custom type

9 posts, 0 answers
  1. Mads
    Mads avatar
    25 posts
    Member since:
    Nov 2014

    Posted 14 Jan 2015 Link to this post

    I am trying to use a custom type in my filter where I want to show all distinct versions of my type in the list, and this works! 


    But when I select a value and try to filter on that value I get an error

    var filter = new FilterDescriptor(dataMember, FilterOperator.IsEqualTo, checkBoxCustomFilterType.Text);

    filter has the value "{PTestType IsEqualTo ks k}" where "ks k" is one of my distint values but its like the PTestType is not converted using the typeconverter? Because then this is thrown 

    An exception of type 'System.ArgumentException' occurred in mscorlib.dll but was not handled in user code

    Additional information: The value "(PTestType IsEqualTo ks k)" is not of type "Telerik.Windows.Data.IFilterDescriptor" and cannot be used in this generic collection.



    Custom type Class

    namespace Systematic.KVK.InseminationPlan.UIL.Details.Windows.TestBucket.DOM
    {
        [TypeConverter(typeof(TestTypeConverter))]
        public class PTestType : IEquatable<PTestType>
        {
            public long Id { get; set; }
            public string ShortTestName { get; set; }
            public string TestName { get; set; }
     
            public bool Equals(PTestType other)
            {
                return Id == other.Id;
            }
     
            public override string ToString()
            {
                return ShortTestName;
            }
     
            public override int GetHashCode()
            {
                return (int)Id;
            }
     
            public override bool Equals(object obj)
            {
                var type = obj as PTestType;
                if (type != null)
                {
                    return Id == type.Id;
                }
     
                return false;
            }
     
            bool IEquatable<PTestType>.Equals(PTestType other)
            {
                if (other == null)
                {
                    return false;
                }
     
                return StringComparer.Ordinal.Equals(Id, other.Id);
            }
        }
    }


    Type converter and valueconverter

    namespace Systematic.KVK.InseminationPlan.UIL.Details.Windows.TestBucket.Tabs.TestBucketTab
    {
        public class PTestTypeConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                var TestType = (PTestType)value;
     
                return TestType.ShortTestName;
            }
     
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
     
        public class TestTypeConverter : TypeConverter
        {
            public TestTypeConverter()
            {
                 
            }
     
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
            {
                return sourceType == typeof(string);
            }
     
            public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
            {
                var stringValue = value as string;
                if (stringValue != null)
                {
                    return new PTestType {Id = 1, TestName = "sdfsdf",ShortTestName = "shortsd"};
                }
     
                return base.ConvertFrom(context, culture, value);
            }
     
            public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
            {
                if (destinationType == typeof(string))
                {
                    return true;
                }
     
                return base.CanConvertTo(context, destinationType);
            }
     
            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
            {
                if (destinationType == typeof(string))
                {
                    return ((PTestType)value).ShortTestName;
                }
     
                return base.ConvertTo(context, culture, value, destinationType);
            }
        }
    }


    My Custom filter codebehind

    namespace Systematic.KVK.InseminationPlan.UIL.Details.Windows.TestBucket.CustomFilters
    {
        public partial class TestTypeCheckBoxFilterControl : IFilteringControl
        {
            public ObservableCollection<CheckBoxCustomFilterType> CustomItems { get; set; }
            private GridViewBoundColumnBase column;
            private CompositeFilterDescriptor compositeFilter;
     
            public TestTypeCheckBoxFilterControl()
            {
                InitializeComponent();
                CustomItems = new ObservableCollection<CheckBoxCustomFilterType>();
                 
                DataContext = this;
            }
     
            private void OnFilter(object sender, RoutedEventArgs e)
            {
                column.DataControl.FilterDescriptors.Clear();
                compositeFilter = new CompositeFilterDescriptor {LogicalOperator = FilterCompositionLogicalOperator.Or};
                var dataMember = column.DataMemberBinding.Path.Path;
                foreach (var checkBoxCustomFilterType in CustomItems)
                {
                    if (checkBoxCustomFilterType.Checked)
                    {
                        var filter = new FilterDescriptor(dataMember, FilterOperator.IsEqualTo, checkBoxCustomFilterType.Text);
                        compositeFilter.FilterDescriptors.Add(filter);
                    }
                }
     
                if (!column.DataControl.FilterDescriptors.Contains(compositeFilter))
                {
                    column.DataControl.FilterDescriptors.Add(compositeFilter);
                }
     
                IsActive = true;
            }
     
            private void OnClear(object sender, RoutedEventArgs e)
            {
                column.DataControl.FilterDescriptors.Clear();
                compositeFilter.FilterDescriptors.Clear();
                CustomItems.ForEach(x => x.Checked = false);
            }
     
            public void Prepare(Telerik.Windows.Controls.GridViewColumn column)
            {
                CustomItems.Clear();
     
                this.column = column as GridViewBoundColumnBase;
     
     
     
                var distinctValues = ((RadGridView)column.Parent).GetDistinctValues(column, false);
     
                foreach (PTestType distinctValue in distinctValues)
                {
                    CustomItems.Add(new CheckBoxCustomFilterType {Checked = false, Text = distinctValue.ToString()});
                }
            }
     
            public bool IsActive { get; set; }
     
            private void SelectAll(object sender, RoutedEventArgs e)
            {
                var checkbox = (sender as CheckBox);
                if (checkbox == null || checkbox.IsChecked == null)
                {
                    return;
                }
     
                foreach (var checkBoxCustomFilterType in CustomItems)
                {
                    checkBoxCustomFilterType.Checked = checkbox.IsChecked.Value;
                }
            }
        }
    }


    My usages of my custom filter

    <telerik:GridViewDataColumn
        DataMemberBinding="{Binding Path=PTestType}"
        IsReadOnly="True"
        IsFilterable="True"
        Header="{x:Static localization:TestBucketTexts.TestType}">
        <telerik:GridViewDataColumn.FilteringControl>
            <customFilters:TestTypeCheckBoxFilterControl />
        </telerik:GridViewDataColumn.FilteringControl>
        <telerik:GridViewDataColumn.CellTemplate>
            <DataTemplate DataType="dom:PBucketModel">
                <TextBlock
                    Text="{Binding Path=PTestType}" />
            </DataTemplate>
        </telerik:GridViewDataColumn.CellTemplate>
    </telerik:GridViewDataColumn>
  2. Mads
    Mads avatar
    25 posts
    Member since:
    Nov 2014

    Posted 16 Jan 2015 in reply to Mads Link to this post

    Any help with this?
  3. UI for WPF is Visual Studio 2017 Ready
  4. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 16 Jan 2015 Link to this post

    Hi,

    The error message says that "(PTestType IsEqualTo ks k)" is not a valid IFilterDescriptor. Generally, I would suggest you defining a custom filtering control instead, you can find the Custom Filtering Controls article for more details.

    You can also refer to this forum thread on Persisting Column Filter where a similar exception was already discussed.

    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.

     
  5. Mads
    Mads avatar
    25 posts
    Member since:
    Nov 2014

    Posted 19 Jan 2015 in reply to Dimitrina Link to this post

    Dimitrina I am already using a custom filter TestTypeCheckBoxFilterControl (The code is in the first post) and I cant get it working, it works fine if my type is string or int, but my custom class do not work and gives me that error
  6. Boris
    Admin
    Boris avatar
    276 posts

    Posted 21 Jan 2015 Link to this post

    Hello,

    Without a provide us with a small runnable project that reproduces your issue, we would be only guessing as to why the  mentioned error occurs. By providing us with such a project we will be able to debug it on our side and be more accurate in our findings. In addition, if you are not entirely sure how to isolate it, you can check this Isolating a problem in a sample project  blog post for some guidance.


    Regards,
    Boris
    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.

     
  7. Mads
    Mads avatar
    25 posts
    Member since:
    Nov 2014

    Posted 22 Jan 2015 in reply to Boris Link to this post

    https://dl.dropboxusercontent.com/u/19153690/TelerikCustomFilter.zip

    The exception is thrown when I try to filter by SomeType

    Also I am in doubt how I am supposed to do this line correctly

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        var stringValue = value as string;
        if (stringValue != null)
        {
            return new SomeType { Id = 1, SomeTypeName = "sdfsdf", ShortSomeTypeName= "shortsd" };
        }
     
        return base.ConvertFrom(context, culture, value);
    }
  8. Boris
    Admin
    Boris avatar
    276 posts

    Posted 26 Jan 2015 Link to this post

    Hi,

    Thank you for the provided project . As it turns out the issue was that you we trying to filter a specific column by a value different than the underlying bound data type. For example your "Some type short name" column is bound to the SomeType property of type SomeType and then you try to filter it by a property of type string. In order to make this work I made the following changes: 

    1) Added a property of type object in your CheckBoxCustomFilterType class. The type is object because your CheckBoxFilterControl control is used for properties of different types (long and SomeType).

    public class CheckBoxCustomFilterType : NotifiableObject
        {
            ...
             
            private object internalSomeType;
            public object InternalSomeType
            {
                get
                {
                    return this.internalSomeType;
                }
                set
                {
                    if (this.internalSomeType != value)
                    {
                        this.internalSomeType = value;
                        RaisePropertyChanged(() => InternalSomeType);
                    }
                }
            }   
             ...   
        }
    }


    2) Updated the Prepare() method of the CheckBoxFilterControl control to pass the distinct value to the newly created property.

    public void Prepare(Telerik.Windows.Controls.GridViewColumn column)
         {
             CustomItems.Clear();
     
             this._column = column as GridViewBoundColumnBase;
     
             var distinctValues = ((RadGridView)column.Parent).GetDistinctValues(column, false);
     
             foreach (object distinctValue in distinctValues)
             {
                 CustomItems.Add(new CheckBoxCustomFilterType { Checked = false, Text = distinctValue.ToString(), InternalSomeType = distinctValue });
             }
         }


    3) Updated the OnFilter() method to add the correct filter value in the FilterDescriptor constructor:

    private void OnFilter(object sender, RoutedEventArgs e)
           {
               if (_compositeFilter != null)
               {
                   _column.DataControl.FilterDescriptors.Remove(_compositeFilter);
               }
     
               _compositeFilter = new CompositeFilterDescriptor { LogicalOperator = FilterCompositionLogicalOperator.Or };
               var dataMember = _column.DataMemberBinding.Path.Path;
               foreach (var checkBoxCustomFilterType in CustomItems)
               {
                   if (checkBoxCustomFilterType.Checked)
                   {
                       var filter = new FilterDescriptor(dataMember, FilterOperator.IsEqualTo, checkBoxCustomFilterType.InternalSomeType);
                       _compositeFilter.FilterDescriptors.Add(filter);
                   }
               }
     
               if (!_column.DataControl.FilterDescriptors.Contains(_compositeFilter))
               {
                   _column.DataControl.FilterDescriptors.Add(_compositeFilter);
               }
     
               IsActive = true;
           }

    I attached an updated version of your project that demonstrates the suggested approach.

    I hope this helps.

    Regards,
    Boris
    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.

     
  9. Mads
    Mads avatar
    25 posts
    Member since:
    Nov 2014

    Posted 03 Feb 2015 in reply to Boris Link to this post

    Fantastic! One last request for now, how can I get the fitler window to close when I click filter or clear?
  10. Boris
    Admin
    Boris avatar
    276 posts

    Posted 04 Feb 2015 Link to this post

    Hi,

    In order to close the filtering popup of the your custom filtering control when you press the Filer or Clear button, you will need to set its IsOpen property to false in their corresponding event handlers:

    private void OnFilter(object sender, RoutedEventArgs e)
            {
               ...
     
                var popup = this.ParentOfType<System.Windows.Controls.Primitives.Popup>();
                if (popup != null)
                {
                    popup.IsOpen = false;
                }
            }
     
            private void OnClear(object sender, RoutedEventArgs e)
            {
                ...
                var popup = this.ParentOfType<System.Windows.Controls.Primitives.Popup>();
                if (popup != null)
                {
                    popup.IsOpen = false;
                }
            }

    A possible way to find the filtering Popup is to use the ParentOfType<T>() extension method.


    Regards,
    Boris
    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
UI for WPF is Visual Studio 2017 Ready