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

Custom filtering

2 Answers 183 Views
DataFilter
This is a migrated thread and some comments may be shown as answers.
Daní
Top achievements
Rank 1
Daní asked on 29 Jul 2010, 03:12 PM
Hi,

I have a Data Collection, PagedCollectionView, Bound to an ItemsControl. Currently, I'm providing to my customers some fast filters, predefined at design time, i.e. filtering when a bool field is true that is activated via a toggle button. Each time users clicks on the toggle my view model object sets the PagedCollectionView.Filter property according the button state.

Now, I'd like to take profit of the RadDataFilter. I want to keep the fast filter funcionality. So the result filter will be an And with the fast filters selected and the DataFilter resulting filter. And I'm facing several problems/doubts with this control;
  1. I want to choose the filterable properties, being able to provide a friendly name, maybe different of than the real name.
  2. Data collection contains complex data, so I'd like to provide any sort of property path like "Property1.Propery3" .
  3. Finally, I'd like to get the resulting expression of the filter, similar to a Predicator<object>

Any help achieving this behaviour? 

2 Answers, 1 is accepted

Sort by
0
Accepted
Rossen Hristov
Telerik team
answered on 30 Jul 2010, 09:39 AM
Hi DanĂ­,

1. You can choose the filterable properties by marking all the rest with the AutoGenerateFilter=false data annotation. Same applies for the friendly name -- RadDataFilter will respect the ShortName data annotation. RadDataFilter "understands" these two data annotations. You will need a reference to System.ComponentModel.DataAnnotations.

2. The only way to define such complex properties is when using RadDataFilter in the so-called Unbound Mode. When in "Unbound Mode", RadDataFilter has no Source. The developer instructs it what properties to show in its drop-downs by assigning its ItemProperties property. This is a collection of ItemPropertyInfo that contains all the information regarding the properties, their type, their attributes and so on.

An example of Unbound Mode can be seen here. Basically, we are telling the filter what props to display and then when its output changes, i.e. the FilterDescriptors collection, we are translating this to a DomainDataSource filter descriptors and performing filtering on the server.

So you can create some ItemPropertyInfo's and feed them to the filter like this:

using System.Collections.Specialized;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Windows.Controls;
using Telerik.Windows.Data;
 
namespace RadDataFilterComplexProperty
{
    public partial class MainPage : UserControl
    {
        /// <summary>
        /// A nice trick you can use to create ANY kind of "fake" property infos.
        /// RadDataFilter will only use their Name, Type and Attributes, so
        /// they really do not need to be the real properties. If you you the
        /// real ones, you might not be able to modify the Attributes for example.
        /// </summary>
        public class CountMetadata
        {
            [Display(AutoGenerateFilter=true, ShortName = "Players Count")]
            public int Count { get; set; }
        }
         
        public MainPage()
        {
            InitializeComponent();
 
            var countPropertyInfo = typeof(CountMetadata).GetProperty("Count");
            var clubPlayersCountInfo = new ItemPropertyInfo("Players.Count"
                , typeof(int)
                , countPropertyInfo);
             
            // This is the "input" for the filter.
            this.dataFilter.ItemProperties = new[] { clubPlayersCountInfo };
 
            // This is the "output" of the filter.
            this.dataFilter.FilterDescriptors.CollectionChanged += this.OnRadDataFilterDescriptorsChanged;
        }
 
        // Since we are in unbound mode, we have to manually synchronize this with the grid.
        // Or with anything else as a matter of fact.
        void OnRadDataFilterDescriptorsChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    this.clubsGrid.FilterDescriptors.AddRange(e.NewItems.OfType<IFilterDescriptor>());
                    break;
                case NotifyCollectionChangedAction.Remove:
                    foreach (var removed in e.OldItems.OfType<IFilterDescriptor>())
                    {
                        this.clubsGrid.FilterDescriptors.Remove(removed);
                    }
                    break;
            }
        }
    }
}

And the XAML:

<UserControl x:Class="RadDataFilterComplexProperty.MainPage"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
             xmlns:my="clr-namespace:RadDataFilterComplexProperty"
             mc:Ignorable="d" d:DesignHeight="700" d:DesignWidth="700">
    <UserControl.Resources>
        <my:MyViewModel x:Key="MyViewModel"/>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot"
          Background="White"
          DataContext="{StaticResource MyViewModel}">
        <Grid.RowDefinitions>
            <RowDefinition Height="50*"/>
            <RowDefinition Height="50*" />
        </Grid.RowDefinitions>
        <telerik:RadDataFilter Name="dataFilter"/>
        <telerik:RadGridView Grid.Row="1"
                             Name="clubsGrid"
                             ItemsSource="{Binding Clubs}"
                             IsFilteringAllowed="False"
                             AutoGenerateColumns="False"
                             Margin="5">
            <telerik:RadGridView.Columns>
                <telerik:GridViewDataColumn DataMemberBinding="{Binding Name}"/>
                <telerik:GridViewDataColumn DataMemberBinding="{Binding Established}" Header="Est." DataFormatString="{}{0:yyyy}"/>
                <telerik:GridViewDataColumn DataMemberBinding="{Binding StadiumCapacity}" Header="Stadium" DataFormatString="{}{0:N0}"/>
                <telerik:GridViewDataColumn DataMemberBinding="{Binding Players.Count}" Header="Players Count" />
            </telerik:RadGridView.Columns>
        </telerik:RadGridView>
    </Grid>
</UserControl>

I have attached a whole sample project that does all of this things in Unbound Mode. Maybe this project will help you start.

By the way, we have a logged a feature request for the ability to define item properties in a declarative way (XAML). You can vote for this feature here. The more votes it gets -- the sooner we will put our resources in it.

3. The output that the filter creates can be read from its property called FilterDescriptors. It is a collection of all the filter descriptors that the user has created. Have in mind that some of them might be CompositeFilterDescriptors, i.e. hierarchical ones. So all the information regarding the filters is in this collection. You can read it and use it for any general purpose.

I hope this helps. Let me know if there are problems.

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
0
Daní
Top achievements
Rank 1
answered on 02 Aug 2010, 01:07 PM
Thanks Ross, it was very helpful
Tags
DataFilter
Asked by
Daní
Top achievements
Rank 1
Answers by
Rossen Hristov
Telerik team
Daní
Top achievements
Rank 1
Share this question
or