Extensions for RadDataFilter

Thread is closed for posting
13 posts, 1 answers
  1. Answer
    OBollmann
    OBollmann avatar
    14 posts
    Member since:
    Jan 2007

    Posted 24 Sep 2010 Link to this post

    Requirements

    RadControls version

    RadControls for WPF Q2 2010 SP1

    .NET version

    4.0

    Visual Studio version

    2010

    programming language

    c#

    browser support

    all browsers supported by RadControls


    PROJECT DESCRIPTION
    I created some extension methods and one helper class for the RadDataFilter WPF-Control. The main goals of the project are:

    • Store and reload current filters as XML
    • Basic support for enums
    • Basic support for object graphs with dot notation

    I think that the usability of the RadDataFilter is extremely high. But for my specific needs I miss some features. In my use case I have business objects that are linked in an object graph (e.g. Customer.Address.Street). I want to implement a rule engine that selects specific business objects with filters that are defined with RadDataFilter control. But for that it must be possible to store and reload filter settings and evaluate filters without the RadDataFilter control in a ViewModel.

    If you use RadDataFilter in "unbound" mode you can define custom ItemPropertyInfos. So it is possible to use dot notation for a complete object graph. But then you don't have binding. The UnboundRadDataFilterHelper class fits this requirement. It is a DependencyObject wich properties are bindable in XAML.

    Further more I have some enum properties in my business objects. I implemented automatic filling of a RadComboBox as editor for enums in RadDataFilter.

    The UnboundRadDataFilterHelper is a generic class which expects a RadDataFilter instance as constructor parameter. The generic type parameter represents the type of the filtered instances. The helper class has a Source and a FilteredSource property like the RadDataFilter control itself. But these properties can be used in "unbound" mode, too. The FilterXml property represents the current filter settings as xml. This property is read- and writeable.

    The Extensions class exposes the following extension methods:

     

    /// <summary>
    /// Serialize CompositeFilterDescriptorCollection to XML
    /// </summary>
    /// <param name="collection">CompositeFilterDescriptorCollection</param>
    /// <typeparam name="T">The type that the filters are based on</typeparam>
    /// <returns>The XML</returns>
    public static XDocument GetXDocument<T>(this CompositeFilterDescriptorCollection collection)
    { ... }
     
    /// <summary>
    /// Serialize IFilterDescriptor
    /// </summary>
    /// <param name="filter">FilterDescriptor</param>
    /// <returns>The XML</returns>
    public static XElement GetXElement(this IFilterDescriptor filter)
    { ... }
     
    /// <summary>
    /// Get FilterDescriptorCollection from XML
    /// </summary>
    /// <param name="document">XML document</param>
    /// <returns>CompositeFilterDescriptorCollection</returns>
    public static CompositeFilterDescriptorCollection GetFilterDescriptorCollection(this XDocument document)
    { ... }

    /// <summary>
    /// Get IFilterDescriptor from XML
    /// </summary>
    /// <param name="element">XML element</param>
    /// <returns>IFilterDescriptor instance</returns>
    public static IFilterDescriptor GetIFilterDescriptor(this XElement element)
    { ... }

    /// <summary>
    /// Set FilterDescriptors in RadDataFilter fom XML document
    /// </summary>
    /// <param name="radDataFilter">RadDataFilter instance</param>
    /// <param name="document">XML document</param>
    public static void SetFilterDescriptors(this RadDataFilter radDataFilter, XDocument document)
    { ... }

    /// <summary>
    /// Get filter method from FilterDescriptor
    /// </summary>
    /// <typeparam name="T">The type that the filter is based on</typeparam>
    /// <param name="filterDescriptor">FilterDescriptor</param>
    /// <returns>Dynamic compiled filter method</returns>
    public static Func<T, bool> GetFilter<T>(this IFilterDescriptor filterDescriptor)
    { ... }

    /// <summary>
    /// Does the filter match?
    /// </summary>
    /// <typeparam name="T">The type that the filter is based on</typeparam>
    /// <param name="item">Filtered item of type T</param>
    /// <param name="filterDescriptor">FilterDescriptor</param>
    /// <returns>Does the filter match?</returns>
    public static bool MatchesFilter<T>(this T item, IFilterDescriptor filterDescriptor)
    { ... }

    /// <summary>
    /// Filter IEnumerable of type T
    /// </summary>
    /// <typeparam name="T">The type the filter is based on</typeparam>
    /// <param name="items">Items of type T</param>
    /// <param name="filterDescriptor">FilterDescriptor</param>
    /// <returns>Get the matched items</returns>
    public static IEnumerable<T> Filter<T>(this IEnumerable<T> items, IFilterDescriptor filterDescriptor)
    { ... }
    I hope it is clear what I tried to say ;-) Any comments are welcome.

    Best regards,
    Oliver

  2. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 28 Sep 2010 Link to this post

    Hi OBollmann,

    You have created something awesome. We really appreciate your commitment.

    By the way, just for the same reason, for the Q3 Release we will obsolete the ItemPropertyInfo and replace it with something called ItemPropertyDefinition. This new class will be a dependency object and you will be able to easily define it both in XAML and code-behind. For example:

    <telerik:RadDataFilter Name="radDataFilter"
                           Grid.Row="0"
                           Source="{Binding Items, ElementName=clubsGrid}"
                           AutoGenerateItemPropertyDefinitions="True"
                           Margin="1">
        <telerik:RadDataFilter.ItemPropertyDefinitions>
            <!--This will also be displayed along with the auto-generated properties.-->
            <datafilter:ItemPropertyDefinition PropertyName="Players.Count"
                                               PropertyType="{x:Type system:Int32}"
                                               DisplayName="Squad Size">
            </datafilter:ItemPropertyDefinition>
        </telerik:RadDataFilter.ItemPropertyDefinitions>
    </telerik:RadDataFilter>

    You can think of there definitions as you would think about grid view columns. You can let RadGridView auto-generate its columns be examining the source or you can define the columns manually. Or you can even mix both.

    The same will apply for RadDataFilter. In the sample above, RadDataFilter will auto-generate all of its definitions based on the source which is a list of football Clubs. Additionaly, I have added a new complex definition called Players.Count having a display name of "Squad Size".

    So when you run RadDataFilter you will see "Squad Size" in the combo-box, which will filter by Players.Count.

    Anyway, the effort that you have made is highly appreciated and I am sure that it will help a lot of fellow developer. I have updated your account with Telerik Points.

    Thank you for your involvement. We are looking forward to hearing from you again.

    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. OBollmann
    OBollmann avatar
    14 posts
    Member since:
    Jan 2007

    Posted 28 Sep 2010 Link to this post

    Hi Ross,

    thanks for your answer. The details about the new ItemPropertyDefinition class sounds very cool! I will give them a try! When will Q3 be released?

    Best regards,
    Oliver
  4. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 28 Sep 2010 Link to this post

    Hello OBollmann,

    We hope to roll it our until the end of November. But I can send you a custom build, since I have already implemented this feature and it has been checked in. Let me know if you would like to play with a custom build in advance.

    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
  5. OBollmann
    OBollmann avatar
    14 posts
    Member since:
    Jan 2007

    Posted 28 Sep 2010 Link to this post

    Oh that would be very helpful for me!

    Thanks!

    Oliver
  6. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 28 Sep 2010 Link to this post

    Hello OBollmann,

    Can you please send a new support ticket, since the Code Library is public and I cannot attach the build here.

    I will attach the build there. Simply indicate "RadDataFilter ItemPropertyDefinitions Custom Build" in the support ticket title and I will handle it from there. Sorry for the inconvenience.

    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
  7. Mike Prager
    Mike Prager avatar
    5 posts
    Member since:
    Sep 2005

    Posted 29 Sep 2010 Link to this post

    Hi Oliver,

    Thanks so much for sharing this as we are alos looking to do something simmilar for a project. Can I just ask, when you select a row in the grid, is it meant to create the filter conditions above the grid i.e. deserialize the filter?

    Thanks again for providing this

    Kind regards

    Mike
  8. OBollmann
    OBollmann avatar
    14 posts
    Member since:
    Jan 2007

    Posted 29 Sep 2010 Link to this post

    Hi Mike,

    I think that I don't exact understand your question. I haven't "played" much with the DataGrid. I use the RadDataFilter mostly without the DataGrid. I use it for filtering internal lists and for evaluating rules on my business objects. I don't have much experience in how the DataGrid interacts with DataFilter :-(

    But perhaps you can clarify your question and I could help you then ...

    Best regards,
    Oliver
  9. Mike Prager
    Mike Prager avatar
    5 posts
    Member since:
    Sep 2005

    Posted 29 Sep 2010 Link to this post

    Hi Oliver,

    Apologies. I did not spend enough time looking at the sample! What I am looking for is how you go from the XML that represents the filter conditions back to the graphical representation of the filter?

    I want to be able to store several of these in a database and then when a user selects one (maybe from a grid), the filter condition is redisplayed?

    Thanks in advance for any help

    Mike
  10. OBollmann
    OBollmann avatar
    14 posts
    Member since:
    Jan 2007

    Posted 29 Sep 2010 Link to this post

    OK ... now it is clear. In the sample project I do exactly that. When you close the program the filter will be serialized as xml in the settings class. When you restart the program the filters will be recreated from this xml in the settings. There are two extension methods that play a central role:

    /// <summary>
    /// Serialize CompositeFilterDescriptorCollection to XML
    /// </summary>
    /// <param name="collection">CompositeFilterDescriptorCollection</param>
    /// <typeparam name="T">The type that the filters are based on</typeparam>
    /// <returns>The XML</returns>
    public static XDocument GetXDocument<T>(this CompositeFilterDescriptorCollection collection)
    { ... }

    /// <summary>
    /// Get FilterDescriptorCollection from XML
    /// </summary>
    /// <param name="document">XML document</param>
    /// <returns>CompositeFilterDescriptorCollection</returns>
    public static CompositeFilterDescriptorCollection GetFilterDescriptorCollection(this XDocument document)
    { ... }


    With these methods you can serialize and deserialize the CompositeFilterDescriptorCollection (FilterDescriptors property on RadDataFilter). If you want to know how the deserialization works exactly you can have a look in the "SetFilterDescriptors" extension method in Extensions.cs in the solution. But you can use the UnboundRadDataFilterHelper class as well. There is the FilterXml property which you can easily get and set. These changes reflects automatically in the DataFilter UI.

    I hope that helps :-D

    Best regards,
    Oliver
  11. Mike Prager
    Mike Prager avatar
    5 posts
    Member since:
    Sep 2005

    Posted 30 Sep 2010 Link to this post

    Hi Oliver,

    That's great. Thanks for clearing that up - It makes sense now!

    Kind regards

    Mike
  12. Lakhwinder
    Lakhwinder avatar
    1 posts
    Member since:
    Oct 2010

    Posted 19 Oct 2010 Link to this post

    How to serialize the Telerik.Windows.Data.FilterDescriptorCollection as a whole object. I am trying the following code and getting error---

    public

     

     

    static string Serialize(Telerik.Windows.Data.FilterDescriptorCollection value)

     

    {

     

     

    if (value == null) return null;

     

     

     

    var serializer = new DataContractSerializer(typeof(Telerik.Windows.Data.FilterDescriptorCollection));

     

     

     

    var stringBuilder = new StringBuilder();

     

     

     

    var writer = XmlWriter.Create(stringBuilder);

     

    serializer.WriteObject(writer, value);

    writer.Flush();

     

     

    return stringBuilder.ToString();

     

    }


    the error is-

    Type 'Telerik.Windows.Controls.GridView.ColumnFilterDescriptor' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required.
  13. Yavor Georgiev
    Admin
    Yavor Georgiev avatar
    982 posts

    Posted 20 Oct 2010 Link to this post

    Hi Lakhwinder,

     Unfortunately some of our Descriptors are complex objects which cannot be serialized without serious tinkering. I suggest that you take a look at this demo, which shows an alternative approach of saving and loading the RadGridView's filter descriptors, which is also applicable to RadDataFilter.
     
    Kind regards,
    Yavor Georgiev
    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
Back to Top