DataFilter & Paging

8 posts, 0 answers
  1. Chi
    Chi avatar
    3 posts
    Member since:
    Feb 2007

    Posted 07 Sep 2010 Link to this post

    I have a very big table containing close to 6000 rows and I want to use the DataFilter control to help me filter data. I am already using a paging control to page the data so I want to find out; if I use DataFilter control will it only filter on the current page or the entire table?
  2. Vlad
    Admin
    Vlad avatar
    11100 posts

    Posted 07 Sep 2010 Link to this post

    Hi,

     If you bind the filter to the already paged data you will get filtering only for the current page however if you bind RadDataFilter to the original data you will get filtering for the entire collection. 

    Kind regards,
    Vlad
    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. DevCraft banner
  4. Jason Davis
    Jason Davis avatar
    3 posts
    Member since:
    Jan 2010

    Posted 04 Oct 2010 Link to this post

    I tried binding as follows:

    Domain Data Source (from EF) => RadDataFilter Source => RadDataFilter FilteredSource => RadDataPager Source => RadDataPager PagedSource => RadGridView ItemsSource.

    This appears as though it retrieves the entire table based on the RadDataFilter filter into the entity set before it does any paging (so it's amazingly slow).

    I also tried as follows:

    Domain Data Source (from EF) => RadDataPager Source => RadDataPager PagedSource =>RadDataFilter Source => RadDataFilter FilteredSource =>  RadGridView ItemsSource.

    This appears as though the paging is executed, and then the filter only works on the current page, so I don't get the expected result set when a filter is applied.

    Can RadDataFilter be used in conjunction with RadDataPager? If so, what's the technique?

  5. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 04 Oct 2010 Link to this post

    Hello Jason Davis,

    RadDataPager can be linked to the DomainDataSource directly like you have done by setting its Source to the DDS.Data property.

    Since Telerik's FilterDescriptors (the things that RadDataFilter produces) are not the same as the DomainDataSource filter descriptors, they need to be translated to the Microsoft ones and then added to the DomainDataSource. This will cause server-side filtering and thin this way you will have both the paging and the filtering executed on the server-side.

    Here is the online example that demonstrates how to connect RadDataFilter to a DomainDataSource and execute the filtering on the server.

    Here is the example that shows how to link RadDataPager to the DomainDataSource and execute paging on the server.

    I hope this helps.

    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
  6. Jason Davis
    Jason Davis avatar
    3 posts
    Member since:
    Jan 2010

    Posted 04 Oct 2010 Link to this post

    Thanks Vlad. I've now got the RadDataFilter => RadDataPager => RadGridView working. There's just one issue that I haven't yet been able to resolve.

    On an initial query, with no filters specified, it works like a treat. As an example, let's say I've got a page size of 20, and it returns 3000 pages. As soon as I specify a filter, however, the number of pages stays the same, but the number of items per page is filtered (rather than the RadDataPager recalculating the pages based on the updated RadDataFilter.FilteredSource. So I'll still have 3000 pages, but some will have less than 20 items per page (corresponding to the filter specified).

    The relevant XAML is as follows:

                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="*" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <riaControls:DomainDataSource Name="SymmetryDomainDataSource"
                                                  QueryName="GetAccountSummariesQuery">
                        <riaControls:DomainDataSource.DomainContext>
                            <domain:SymmetryDomainContext />
                        </riaControls:DomainDataSource.DomainContext>
                    </riaControls:DomainDataSource>
                    <Border telerikQuickStart:ThemeAwareBackgroundBehavior.IsEnabled="True"
                            Grid.Row="0"
                            Grid.RowSpan="3" />
                    <telerik:RadDataFilter Name="AccountSummaryFilter"
                                           Grid.Row="0"
                                           Source="{Binding Data, ElementName=SymmetryDomainDataSource}"
                                           Margin="10 10 10 0" />
                    <telerik:RadGridView Name="AccountSummaryGrid"
                                         Grid.Row="1"
                                         ItemsSource="{Binding PagedSource, ElementName=AccountSummaryPager}"
                                         stargateCommands:TelerikDataControlSelected.Command="{Binding}"
                                         AutoGenerateColumns="False"
                                         AutoExpandGroups="True"
                                         ShowGroupPanel="False"
                                         ShowInsertRow="False"
                                         IsFilteringAllowed="False"
                                         CanUserDeleteRows="False"
                                         CanUserInsertRows="False"
                                         CanUserFreezeColumns="False"
                                         CanUserSortColumns="False"
                                         IsReadOnly="True"
                                         Margin="10 10 10 0"
                                         ColumnWidth="100">
                        <telerik:RadGridView.SortDescriptors>
                            <telerik:SortDescriptor Member="AccountName"
                                                    SortDirection="Ascending" />
                        </telerik:RadGridView.SortDescriptors>
                        <telerik:RadGridView.Columns>
                            <telerik:GridViewDataColumn Header="Account Id"
                                                        DataMemberBinding="{Binding AccountID}"
                                                        Width="80" />
                            <telerik:GridViewDataColumn Header="Account Name"
                                                        DataMemberBinding="{Binding AccountName}"
                                                        Width="160" />
                            <telerik:GridViewDataColumn Header="Account Type"
                                                        DataMemberBinding="{Binding AccountType}"
                                                        Width="140" />
                            <telerik:GridViewDataColumn Header="Status"
                                                        DataMemberBinding="{Binding Status}"
                                                        Width="120" />
                            <telerik:GridViewDataColumn Header="Assigned To"
                                                        DataMemberBinding="{Binding AssignedTo}"
                                                        Width="160" />
                            <telerik:GridViewDataColumn Header="Date Created"
                                                        DataMemberBinding="{Binding DateCreated}"
                                                        DataFormatString="{}{0:d}" />
                        </telerik:RadGridView.Columns>
                    </telerik:RadGridView>
                    <telerik:RadDataPager Name="AccountSummaryPager"
                                          Source="{Binding FilteredSource, ElementName=AccountSummaryFilter}"
                                          Grid.Row="2"
                                          PageSize="20"
                                          DisplayMode="All"
                                          AutoEllipsisMode="Both"
                                          NumericButtonCount="10"
                                          IsTotalItemCountFixed="True"
                                          Margin="10 10 10 10">
                    </telerik:RadDataPager>
                </Grid>
  7. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 05 Oct 2010 Link to this post

    Hello Jason Davis,

    That is because you are still not doing filtering on the server. Please, read my previous post carefully.

    Anyway, I will try to explain this once more.

    You have to use the RadDataFilter to filter the DomainDataSource (Server). But you cannot do this directly by writing:

    Source="{Binding Data, ElementName=SymmetryDomainDataSource}"
    
    This will not work!
    

    As I have already explained, Telerik's FilterDescriptors (the stuff RadDataFilter produces) are different from Microsoft's (the stuff DomainDataSource consumes).

    That is why you have to translate Telerik's FilterDescriptors to Microsoft ones and then add them to the DomainDataSource. Your RadDataFilter will in fact be Unbound, i.e. it will have no Source defined.

    This is clearly demonstrated in the online example link that I have already provided. Please, examine it carefully.

    By the way, we are currently working on our very own DomainDataSource control. When it is released all of this hassle will not longer be needed and you will be able to do everything on the server, i.e. filtering, paging and sorting without the need to write any additional code. Until then you will have to translate our descriptors to MS descriptors like in the online example.

    I hope this helps. Let me know if you have any other questions.

    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
  8. Jason Davis
    Jason Davis avatar
    3 posts
    Member since:
    Jan 2010

    Posted 06 Oct 2010 Link to this post

    Hi Ross,

    My apologies: I was looking at the wrong sample.

    FYI, I have implemented the functionality in the sample, which works great, but didn't want to do it in the code behind as I'm pretty anal about sticking to our internal MVVM framework. As such, I recreated the functionality as an attached property on the DomainDataSource. The XAML for the domain data source becomes:

    <riaControls:DomainDataSource Name="SymmetryDomainDataSource"
                                  AutoLoad="True"
                                  mvvm:DomainDataSource.RadDataFilter="{Binding ElementName=AccountSummaryFilter}"
                                  QueryName="GetAccountSummariesQuery">
        <riaControls:DomainDataSource.DomainContext>
    <domain:SymmetryDomainContext />
    </riaControls:DomainDataSource.DomainContext>
    </riaControls:DomainDataSource>

    which I think is reasonably intuitive. The code for the attached property is given below, in case anyone's interested:

    #region Using directives
    using Stargate.Silverlight.Mvvm.Constants;
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Linq;
    using System.Reflection;
    using System.ServiceModel.DomainServices.Client;
    using System.Windows;
    using Telerik.Windows.Controls;
    using Telerik.Windows.Controls.Data;
    using Telerik.Windows.Data;
    using SystemControls = System.Windows.Controls;
    using TelerikData = Telerik.Windows.Data;
    #endregion

    namespace Stargate.Silverlight.Mvvm
    {
        #region Domain data source
        public class DomainDataSource
        {
            #region RadDataFilter property
            public static readonly DependencyProperty RadDataFilterProperty =
                DependencyProperty.RegisterAttached(
                DependencyPropertyName.RadDataFilter,
                typeof(RadDataFilter),
                typeof(DomainDataSource),
                new PropertyMetadata(HandleRadDataFilterPropertyChanged));
            #endregion

            #region Set RadDataFilter
            public static void SetRadDataFilter(DependencyObject obj, RadDataFilter filter)
            {
                obj.SetValue(DomainDataSource.RadDataFilterProperty, filter);
            }
            #endregion

            #region Get RadDataFilter
            public static RadDataFilter GetRadDataFilter(DependencyObject obj)
            {
                return obj.GetValue(DomainDataSource.RadDataFilterProperty) as RadDataFilter;
            }
            #endregion

            #region Filter map property
            public static readonly DependencyProperty FilterMapProperty =
                DependencyProperty.RegisterAttached(
                DependencyPropertyName.FilterMap,
                typeof(Dictionary<TelerikData.FilterDescriptor, SystemControls.FilterDescriptor>),
                typeof(DomainDataSource),
                new PropertyMetadata(new Dictionary<TelerikData.FilterDescriptor, SystemControls.FilterDescriptor>()));
            #endregion

            #region Set filter map
            public static void SetFilterMap(DependencyObject obj, Dictionary<TelerikData.FilterDescriptor, SystemControls.FilterDescriptor> filterMap)
            {
                obj.SetValue(DomainDataSource.FilterMapProperty, filterMap);
            }
            #endregion

            #region Get filter map
            public static Dictionary<TelerikData.FilterDescriptor, SystemControls.FilterDescriptor> GetFilterMap(DependencyObject obj)
            {
                return obj.GetValue(DomainDataSource.FilterMapProperty) as Dictionary<TelerikData.FilterDescriptor, SystemControls.FilterDescriptor>;
            }
            #endregion

            #region Handle RadDataFilter property changed
            public static void HandleRadDataFilterPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
            {
                var domainDataSource = obj as SystemControls.DomainDataSource;
                var filter = e.NewValue as RadDataFilter;
                if (filter != null && domainDataSource != null)
                    ProcessRadDataFilterPropertyChanged(domainDataSource, filter);
            }
            #endregion

            #region Process RadDataFilter property changed
            public static void ProcessRadDataFilterPropertyChanged(SystemControls.DomainDataSource domainDataSource, RadDataFilter filter)
            {
                    MethodInfo queryMethod = domainDataSource.DomainContext.GetType().GetMethod(domainDataSource.QueryName);
                    if (queryMethod != null)
                    {
                        var query = queryMethod.Invoke(domainDataSource.DomainContext, nullas EntityQuery;
                        if (query != null)
                        {
                            filter.CanUserCreateCompositeFilters = false;
                            domainDataSource.LoadedData += (sender, e) =>
                            {
                                //TODO: Expose this as an attached DelegateCommand<LoadedDataEventArgs> so it can be
                                //      bound to a ViewModel.

                                if (e.HasError)
                                {
                                    //Avoid showing exceptions when data exceeds URI length limitations /e.g adding too many filter descriptors/
                                    e.MarkErrorAsHandled();
                                }
                            };

                            IEnumerable<ItemPropertyInfo> itemProperties = query.EntityType.ToItemProperties();
                            filter.ItemProperties = itemProperties;

                            ICompositeFilterDescriptor cfd = filter.FilterDescriptors;
                            domainDataSource.FilterOperator = CreateRiaLogicalOperator(cfd.LogicalOperator);
                            filter.FilterDescriptors.PropertyChanged += (sender, e) =>
                            {
                                ICompositeFilterDescriptor desc = (ICompositeFilterDescriptor)sender;
                                if (e.PropertyName == Constants.PropertyName.LogicalOperator)
                                {
                                    domainDataSource.FilterOperator = CreateRiaLogicalOperator(desc.LogicalOperator);
                                }
                            };
                            filter.FilterDescriptors.CollectionChanged += (sender, e) =>
                            {
                                ICompositeFilterDescriptor desc = (ICompositeFilterDescriptor)sender;

                                switch (e.Action)
                                {
                                    case NotifyCollectionChangedAction.Add:
                                        foreach (TelerikData.FilterDescriptor filterDescriptor
                                            in e.NewItems.OfType<Telerik.Windows.Data.FilterDescriptor>())
                                        {
                                            AddFilter(filterDescriptor, domainDataSource);
                                        }
                                        break;
                                    case NotifyCollectionChangedAction.Remove:
                                        foreach (TelerikData.FilterDescriptor filterDescriptor
                                            in e.OldItems.OfType<Telerik.Windows.Data.FilterDescriptor>())
                                        {
                                            RemoveFilter(filterDescriptor, domainDataSource);
                                        }
                                        break;
                                    case NotifyCollectionChangedAction.Reset:
                                        domainDataSource.FilterDescriptors.Clear();
                                        foreach (TelerikData.FilterDescriptor filterDescriptor in desc.FilterDescriptors)
                                        {
                                            AddFilter(filterDescriptor, domainDataSource);
                                        }
                                        break;
                                }
                            };
                        }
                    }
            }
            #endregion

            #region Add filter
            private static void AddFilter(TelerikData.FilterDescriptor filterDescriptor, SystemControls.DomainDataSource domainDataSource)
            {
                var filterMap = GetFilterMap(domainDataSource);

                SystemControls.FilterDescriptor riaFilterDescriptor =
                    CreateRiaFilterDescriptor(filterDescriptor);

                filterMap[filterDescriptor] = riaFilterDescriptor;

                filterDescriptor.PropertyChanged += (sender, e) =>
                {
                    ProcessFilterDescriptorPropertyChanged((TelerikData.FilterDescriptor)sender, e.PropertyName, domainDataSource);
                };

            }
            #endregion

            #region Remove filter
            private static void RemoveFilter(TelerikData.FilterDescriptor filterDescriptor, SystemControls.DomainDataSource domainDataSource)
            {
                var filterMap = GetFilterMap(domainDataSource);

                SystemControls.FilterDescriptor riaFilterDescriptor = filterMap[filterDescriptor];

                filterMap[filterDescriptor] = null;

                filterDescriptor.PropertyChanged -= (sender, e) =>
                {
                    ProcessFilterDescriptorPropertyChanged((TelerikData.FilterDescriptor)sender, e.PropertyName, domainDataSource);
                };

                domainDataSource.FilterDescriptors.Remove(riaFilterDescriptor);
            }
            #endregion

            #region Process filter descriptor property changed
            private static void ProcessFilterDescriptorPropertyChanged(
                TelerikData.FilterDescriptor filterDescriptor,
                string propertyName,
                SystemControls.DomainDataSource domainDataSource)
            {
                var filterMap = GetFilterMap(domainDataSource);
                SystemControls.FilterDescriptor riaFilterDescriptor = filterMap[filterDescriptor];

                switch (propertyName)
                {
                    case Constants.PropertyName.Member:
                        riaFilterDescriptor.PropertyPath = filterDescriptor.Member;
                        break;
                    case Constants.PropertyName.Operator:
                        riaFilterDescriptor.Operator = CreateRiaOperator(filterDescriptor.Operator);
                        break;
                    case Constants.PropertyName.Value:
                        if (filterDescriptor.Value == null
                            && filterDescriptor.Operator != Telerik.Windows.Data.FilterOperator.IsEqualTo
                            && filterDescriptor.Operator != Telerik.Windows.Data.FilterOperator.IsNotEqualTo)
                        {
                            filterDescriptor.Value = Telerik.Windows.Data.FilterDescriptor.UnsetValue;
                        }

                        riaFilterDescriptor.Value = filterDescriptor.Value;

                        if (!FilterDescriptor.UnsetValue.Equals(riaFilterDescriptor.Value)
                            && !domainDataSource.FilterDescriptors.Contains(riaFilterDescriptor))
                        {
                            domainDataSource.FilterDescriptors.Add(riaFilterDescriptor);
                        }

                        break;
                    case Constants.PropertyName.IsCaseSensitive:
                        riaFilterDescriptor.IsCaseSensitive = filterDescriptor.IsCaseSensitive;
                        break;
                }
            }
            #endregion

            #region Create RIA operator
            private static SystemControls.FilterOperator CreateRiaOperator(TelerikData.FilterOperator filterOperator)
            {
                return (SystemControls.FilterOperator)Enum.Parse(typeof(SystemControls.FilterOperator), filterOperator.ToString(), true);
            }
            #endregion

            #region Create RIA logical operator
            private static SystemControls.FilterDescriptorLogicalOperator CreateRiaLogicalOperator(TelerikData.FilterCompositionLogicalOperator logicalOperator)
            {
                return (SystemControls.FilterDescriptorLogicalOperator)Enum.Parse(typeof(TelerikData.FilterCompositionLogicalOperator), logicalOperator.ToString(), true);
            }
            #endregion

            #region Create RIA filter descriptor
            private static System.Windows.Controls.FilterDescriptor CreateRiaFilterDescriptor(TelerikData.FilterDescriptor filterDescriptor)
            {
                SystemControls.FilterDescriptor riaFilterDescriptor = new SystemControls.FilterDescriptor();
                riaFilterDescriptor.PropertyPath = filterDescriptor.Member;
                riaFilterDescriptor.Operator = CreateRiaOperator(filterDescriptor.Operator);
                riaFilterDescriptor.Value = filterDescriptor.Value;
                riaFilterDescriptor.IsCaseSensitive = filterDescriptor.IsCaseSensitive;

                riaFilterDescriptor.IgnoredValue = Telerik.Windows.Data.FilterDescriptor.UnsetValue;

                return riaFilterDescriptor;
            }
            #endregion
        }
        #endregion
    }
  9. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 07 Oct 2010 Link to this post

    Hello Jason Davis,

    That is a neat implementation. I hope that when we roll our own DomainDataSource out all of this will not be needed anymore. But anyway, attached properties are really powerful for this kind of stuff. It's code-behind again -- but in a different place :)

    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
Back to Top
DevCraft banner