RadDataFilter Storage

18 posts, 0 answers
  1. Sean
    Sean avatar
    2 posts
    Member since:
    Jul 2010

    Posted 12 Aug 2010 Link to this post

    Hi All!

      I figured I would post here instead of a trouble ticket as this really is a quest for information more than anything else.  I am sure that you have probably been asked this somewhere by now; but I am not finding anything in the documentation or via the support links, so here it goes!

    I have a GridView that is attached to a RadDataFilter and I would like to be able to store in a database the FilterDescriptors and the Logical operators that a user adds/changes/modifies.  I am having a hard time trying to figure out the bes data structure to use to accommodate the storing and retrieval of these filters.  My RadGridView is tied to a view in the database and these filters will be extremely important to keep for the filtering process.

    Can someone make a recommendation as to the best approach?  Is there an easy way to "re-build" the RadDataFilter based on the string value found when assessing the values in this property: "radDataFilter.ViewModel.CompositeFilter.ToString()"?  If not a solution could be XML?  Just not sure what is less painful when attempting to store this controls data.  Perhaps I have to store the Binary for the object in the DB and rebuild?

    Any assistance or guidance is greatly appreciated!

    Thanks!

    -Sean

  2. Sean
    Sean avatar
    2 posts
    Member since:
    Jul 2010

    Posted 13 Aug 2010 Link to this post

    OK after a good long day I got this working.  Now just having issues with REALLY slow adding and removing of filters.
  3. UI for WPF is Visual Studio 2017 Ready
  4. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 16 Aug 2010 Link to this post

    Hi Sean,

    How are you doing this? Can you share a little bit more and maybe send a sample project if possible.

    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
  5. Alex Peachey
    Alex Peachey avatar
    56 posts
    Member since:
    May 2006

    Posted 23 Aug 2010 Link to this post

    I'd like to know the best way to do this as well. I also need to persist filter sets in our database. Basically what I've built is a mailing list generator. The user can use the DataFilter to narrow down the entire list based on demographics and other attributes and then export this list for use in the mailing.

    I want to be able to have them save the filter sets though so they can basically re-run the same "query" in the future without having to re-build it.
  6. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 24 Aug 2010 Link to this post

    Hello Alex Peachey,

    You can try serializing the descriptors by using the DataContractSerializer.

    In .NET 3.5 SP1 and .NET 4.0 the attributes are not longer needed as described in this article.

    I hope this helps.

    Best wishes,
    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
  7. Alex Peachey
    Alex Peachey avatar
    56 posts
    Member since:
    May 2006

    Posted 24 Aug 2010 Link to this post

    I tried this code:
    var serializer = new DataContractSerializer(typeof(CompositeFilterDescriptorCollection));
                 var stream = new MemoryStream();
                 serializer.WriteObject(stream, ContactFilter.FilterDescriptors);
                 var encoding = new UTF8Encoding();
               var serializedFilters = encoding.GetString(stream.ToArray());

    I ran into problems though as it complained about KnownTypes and FilterDescriptor. So I modified my code:
    var serializer = new DataContractSerializer(typeof(CompositeFilterDescriptorCollection), new List<Type> { typeof(FilterDescriptor) });

    I run again and find now it complains about KnownTypes and System.RuntimeType.

    I don't think it's actually choking on RuntimeType as that is an internal class but rather it's getting bogged up on something else.

    It would definitely be a great solution if we could just serialize these FilterDescriptors and re-hydrate as needed.


  8. Alex Peachey
    Alex Peachey avatar
    56 posts
    Member since:
    May 2006

    Posted 24 Aug 2010 Link to this post

    Ok, maybe there is a good built in way, maybe there isn't, but not wanting to wait around for further feedback, I figured the easiest thing to do would be to just create alternate structures to store the Filter info in and then serialize those and rehydrate as necessary. It works like a champ!

    For others that want to do the same, this is what I did:

    public interface IFilter
        {}
     
        public class FilterSet : IFilter
        {
            public List<IFilter> Filters;
            public FilterCompositionLogicalOperator Operator { get; set; }
        }
     
        public class Filter : IFilter
        {
            public bool IsCaseSensitive { get; set; }
            public string Member { get; set; }
            public object Value { get; set; }
            public FilterOperator Operator { get; set; }
        }

    Then I have these two methods in my code behind:
    private List<IFilter> GetFiltersFromFilterDescriptors(IEnumerable<IFilterDescriptor> list)
            {
                var results = new List<IFilter>();
                foreach (var item in list)
                {
                    var cdf = item as CompositeFilterDescriptor;
                    if (cdf != null)
                    {
                        var fs = new FilterSet
                                     {
                                         Operator = cdf.LogicalOperator,
                                         Filters = GetFiltersFromFilterDescriptors(cdf.FilterDescriptors.ToList())
                                     };
                        results.Add(fs);
                    }
                    else
                    {
                        var df = item as FilterDescriptor;
                        if (df != null && !df.Value.GetType().ToString().Equals("Telerik.Windows.Data.FilterDescriptor+FilterDescriptorUnsetValue"))
                        {
                            var f = new Filter
                                        {
                                            IsCaseSensitive = df.IsCaseSensitive,
                                            Member = df.Member,
                                            Operator = df.Operator,
                                            Value = df.Value
                                        };
                            results.Add(f);
                        }
                    }
                }
                return results;
            }
     
            private IEnumerable<IFilterDescriptor> GetFilterDescriptorsFromFilters(IEnumerable<IFilter> list)
            {
                var results = new List<IFilterDescriptor>();
                foreach (var item in list)
                {
                    var fs = item as FilterSet;
                    if (fs != null)
                    {
                        var cdf = new CompositeFilterDescriptor
                                      {LogicalOperator = fs.Operator, FilterDescriptors = new FilterDescriptorCollection()};
                        cdf.FilterDescriptors.AddRange(GetFilterDescriptorsFromFilters(fs.Filters));
                        results.Add(cdf);
                    }
                    else
                    {
                        var f = item as Filter;
                        if (f != null)
                        {
                            var df = new FilterDescriptor
                                         {
                                             IsCaseSensitive = f.IsCaseSensitive,
                                             Member = f.Member,
                                             Operator = f.Operator,
                                             Value = f.Value
                                         };
                            results.Add(df);
                        }
                    }
                }
                return results;
            }

    Just to test it out I made a Serialize and a Rehydrate button with the following event handlers:
    private void Serialize(object sender, RoutedEventArgs e)
            {
                _filterSet = new FilterSet { Operator = ContactFilter.FilterDescriptors.LogicalOperator, Filters = GetFiltersFromFilterDescriptors(ContactFilter.FilterDescriptors.ToList()) };
                var serializer = new DataContractSerializer(typeof(FilterSet), new List<Type> { typeof(Filter) });
                var stream = new MemoryStream();
                serializer.WriteObject(stream, _filterSet);
                var encoding = new UTF8Encoding();
                var serializedFilters = encoding.GetString(stream.ToArray());
                _storage = serializedFilters;
            }
            private void Rehydrate(object sender, RoutedEventArgs e)
            {
                var serializer = new DataContractSerializer(typeof(FilterSet), new List<Type> { typeof(Filter) });
                var encoding = new UTF8Encoding();
                var stream = new MemoryStream(encoding.GetBytes(_storage));
                var fs = (FilterSet)serializer.ReadObject(stream);
                ContactFilter.FilterDescriptors.Clear();
                ContactFilter.FilterDescriptors.LogicalOperator = fs.Operator;
                ContactFilter.FilterDescriptors.AddRange(GetFilterDescriptorsFromFilters(fs.Filters));
            }

    For test purposes this was just storing in a private string variable but the result is xml and can be dumped to a file, into a database, or whatever.
  9. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 25 Aug 2010 Link to this post

    Hello Alex Peachey,

    That's really cool.

    By the way, MS claim that in the latest version of .NET you can serialize third-party classes (FilterDescriptor in your case) without adding any attributes to them (since they are not under your control).

    Have you tried to serialize our descriptors directly instead of creating a mirror class for them. I am just curious?

    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
  10. Alex Peachey
    Alex Peachey avatar
    56 posts
    Member since:
    May 2006

    Posted 25 Aug 2010 Link to this post

    I didn't try under 4.0 as my project is 3.5sp1 but I did try under 3.5sp1 and I mentioned that attempt in the previous post. Where I ran into the complaint about RuntimeType.

    Doing some digging on Google, I'm not positive but I suspect the problem is that your DataFilter class has a property called MemberType which is of type Type. Based on what I've read it sounds like Type doesn't serialize well (or maybe at all).

    So in order to serialize your classes, I'm pretty sure you need to either not include that property in the serialization or do a transform into a string or something and transform back later.

    You'll notice I left MemberType out of my solution as I know I wouldn't need it in my project and suspected it to be part of the problem. To be thoroughly compatible I would have had to make my mirror class have a string property for type and convert to and from string.
  11. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 25 Aug 2010 Link to this post

    Hi Alex Peachey,

    You are right. We have a property of type Type called MemberType. But it is only needed when we filter our QueryableCollectionView which is not the case since RadDataFilter is in Unbound Mode.

    In your case, since you do not need the MemberType, I guess that copying the contents of the original descriptors to your mirror class would be the best approach for serialization.

    Thank you for sharing this info with us.

    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
  12. Naresh
    Naresh avatar
    31 posts
    Member since:
    Mar 2009

    Posted 13 Sep 2010 Link to this post

    Alex,

    Thank you very much for sharing this code. We have the same requirement for a Silverlight 4 project. You have saved us a bunch of time!

    For anyone that ports this to Silverlight, please be aware that you need to change encoding.GetString(stream.ToArray()); to encoding.GetString(stream.ToArray(), 0, stream.ToArray()
    .Length);

    Thanks again,
    Brian

  13. satish
    satish avatar
    6 posts
    Member since:
    Sep 2010

    Posted 17 Nov 2010 Link to this post

    thanks for sharing code,
    when i tried to use the code it failed at  below line with error :

    code :

    dataFilter.FilterDescriptors.AddRange(GetFilterDescriptorsFromFilters(fs.Filters));

    error:

    Cannot change ObservableCollection during a CollectionChanged or PropertyChanged event.


    can some one please help me

    thanks in advance
    sam
  14. Richard Harrigan
    Richard Harrigan avatar
    235 posts
    Member since:
    Nov 2009

    Posted 15 Aug 2011 Link to this post

    Hi Alex,

    I am trying to use your code in a Silverlight 4 project but the following line does not compile.  LogicalOperator and ToList() are not available. See below.  I defined ContactFilter as CompositeFilterDescriptor.

    filterSet = new FilterSet { Operator = ContactFilter.FilterDescriptors.LogicalOperator, Filter = GetFiltersFromFilterDescriptors(ContactFilter.FilterDescriptors.ToList()) };

    If possible can you help me out here.

    Thanks
    Rich
  15. Tony
    Tony avatar
    1 posts
    Member since:
    Nov 2011

    Posted 15 Nov 2011 Link to this post

    Hi rich!
    If you haven't already figured it out, then this is for everyone else's benefit who might still be struggling with the code.
    To answer your question, since GetFiltersFromFilterDescriptors gets as a parameter a list, I believe that the toList() function for FilterDescriptors was phased out because its already a list. Therefore, you could just simply use

    var _filterSet = new FilterSet { Operator = CurrentView.ContactFilter.FilterDescriptors.LogicalOperator, Filters = GetFiltersFromFilterDescriptors(CurrentView.ContactFilter.FilterDescriptors) };

    Tony
  16. Zack
    Zack avatar
    112 posts
    Member since:
    Jun 2012

    Posted 10 Apr 2012 Link to this post

    Have you ever tried operators like "Starts With" or "Contains"?
    I get "The method or operation is not implemented" errors (on deserializing and loading) when doing things other than simple equals etc...

    **Edit
    I believe my issue is due to the MemberType autdetection not working with DataRow which my filter is based on. I am now trying to find the best way to set the MemberType for each descriptor.

    **Edit - Solution
    Ok I put it in the GetFilterDescriptorsFromFilters method for each FilterDescriptor. I was going to do it when the filter item was created but the serialization method doesn't take membertype so it seemed to me that it had to be done at "rehydration" time. This may not be the optimal solution but it works for me since our data is dynamic sql query based datatables. Hope this helps others in my situation!
  17. Zack
    Zack avatar
    112 posts
    Member since:
    Jun 2012

    Posted 24 Aug 2012 Link to this post

    We now have another problem.This method of reloading the filter deserialized works very well but sometimes when we do it the filteredsource will show zero rows when there are no filters loaded. You can query it and it has 1000+ items in the Source but FilteredSource is 0 and there are no filters shown in the datafilter control... anything I can check or refresh to keep this from happening?

    **Edit - Solution
    We use the filter.filteredsource bound to a radgridview.itemsource and the datasource would change in terms of columns (datatable based) so it turned out if we have a sortdescriptor(s) on the grid and attempted to deserialize a datafilter that was bound to the grid which contained sortdescriptors for the columns that no longer existed in the datafilter or grid it would just result in the datafilter.filtered source = 0... so long story short make sure if you reuse the grid and datafilter to flush desrciptors before rebuilding with things like serialized objects.
  18. madladuk
    madladuk avatar
    126 posts
    Member since:
    Dec 2009

    Posted 28 Oct 2012 Link to this post

    works a treat in Silverlight, thanks for the code, been looking to save/restore the filters for some time :-)

    P
  19. Zack
    Zack avatar
    112 posts
    Member since:
    Jun 2012

    Posted 30 Jan 2013 Link to this post

    For other struggling with this I think I found a better solution for our needs involving datatable and datafilter. Posted it here: http://www.telerik.com/community/forums/wpf/persistence-framework/datafilter-persisted.aspx#2470220
Back to Top
UI for WPF is Visual Studio 2017 Ready