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

RadDataFilter Storage

17 Answers 494 Views
DataFilter
This is a migrated thread and some comments may be shown as answers.
Sean
Top achievements
Rank 1
Sean asked on 12 Aug 2010, 03:42 PM
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

17 Answers, 1 is accepted

Sort by
0
Sean
Top achievements
Rank 1
answered on 13 Aug 2010, 04:45 PM
OK after a good long day I got this working.  Now just having issues with REALLY slow adding and removing of filters.
0
Rossen Hristov
Telerik team
answered on 16 Aug 2010, 08:28 AM
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
0
Alex Peachey
Top achievements
Rank 1
answered on 23 Aug 2010, 11:05 PM
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.
0
Rossen Hristov
Telerik team
answered on 24 Aug 2010, 09:05 AM
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
0
Alex Peachey
Top achievements
Rank 1
answered on 24 Aug 2010, 05:14 PM
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.


0
Alex Peachey
Top achievements
Rank 1
answered on 24 Aug 2010, 07:11 PM
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.
0
Rossen Hristov
Telerik team
answered on 25 Aug 2010, 08:30 AM
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
0
Alex Peachey
Top achievements
Rank 1
answered on 25 Aug 2010, 02:43 PM
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.
0
Rossen Hristov
Telerik team
answered on 25 Aug 2010, 02:58 PM
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
0
Naresh
Top achievements
Rank 1
answered on 13 Sep 2010, 03:45 PM
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

0
satish
Top achievements
Rank 1
answered on 17 Nov 2010, 08:59 AM
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
0
Richard Harrigan
Top achievements
Rank 1
answered on 15 Aug 2011, 08:25 PM
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
0
Tony
Top achievements
Rank 1
answered on 15 Nov 2011, 10:48 PM
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
0
Guru
Top achievements
Rank 2
answered on 11 Apr 2012, 12:24 AM
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!
0
Guru
Top achievements
Rank 2
answered on 24 Aug 2012, 03:29 PM
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.
0
madladuk
Top achievements
Rank 2
answered on 28 Oct 2012, 10:32 AM
works a treat in Silverlight, thanks for the code, been looking to save/restore the filters for some time :-)

P
0
Guru
Top achievements
Rank 2
answered on 31 Jan 2013, 12:11 AM
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
Tags
DataFilter
Asked by
Sean
Top achievements
Rank 1
Answers by
Sean
Top achievements
Rank 1
Rossen Hristov
Telerik team
Alex Peachey
Top achievements
Rank 1
Naresh
Top achievements
Rank 1
satish
Top achievements
Rank 1
Richard Harrigan
Top achievements
Rank 1
Tony
Top achievements
Rank 1
Guru
Top achievements
Rank 2
madladuk
Top achievements
Rank 2
Share this question
or