Filtering and Grouping

Aug 29, 2008 at 2:52 PM
Edited Aug 29, 2008 at 3:01 PM
Hi,

 Here is my code for grouping and filtering:

        #region Filtering

        /// <summary>
        /// Method for filtering a grid
        /// </summary>
        /// <param name="dataGridColumn"></param>
        internal void PerformFilter(DataGridColumn filterColumn)
        {
            Debug.Assert(filterColumn != null, "Column should not be null");

            // fire on filter event
            DataGridFilterEventArgs eventArgs = new DataGridFilterEventArgs(filterColumn);
            OnFiltering(eventArgs);

            if (Items.NeedsRefresh)
            {
                try
                {
                    Items.Refresh();
                }
                catch (InvalidOperationException invalidOperationException)
                {
                    throw new InvalidOperationException(SR.Get(SRID.DataGrid_ProbableInvalidFilterDescription), invalidOperationException);
                }
            }
        }

        public event DataGridFilterEventHandler Filter;

        /// <summary>
        /// Protected method that raises the Filter event and calls the default filter method
        /// </summary>
        /// <param name="eventArgs"></param>
        protected void OnFiltering(DataGridFilterEventArgs eventArgs)
        {
            eventArgs.Handled = false;
            if (Filter != null)
            {
                Filter(this, eventArgs);
            }

            if (!eventArgs.Handled)
            {
                DefaultFilter(eventArgs.Column);
            }
        }

        /// <summary>
        /// Performe default sort
        /// </summary>
        /// <param name="dataGridColumn"></param>
        private void DefaultFilter(DataGridColumn column)
        {
            ICollectionView collectionView = CollectionViewSource.GetDefaultView(Items);

            string filterDataPath = column.FilterMemberPath;

            if (string.IsNullOrEmpty(filterDataPath))
            {
                DataGridBoundColumn boundColumn = column as DataGridBoundColumn;
                if (boundColumn != null)
                {
                    Binding binding = boundColumn.DataFieldBinding as Binding;
                    if (binding != null)
                    {
                        if (!string.IsNullOrEmpty(binding.XPath))
                        {
                            filterDataPath = binding.XPath;
                        }
                        else if (binding.Path != null)
                        {
                            filterDataPath = binding.Path.Path;
                        }
                    }
                }
            }

            string filter = column.Filter;

            collectionView.Filter = delegate(object item)
            {
                PropertyDescriptorCollection props = TypeDescriptor.GetProperties(item);
                PropertyDescriptor fprop = (from prop in props.Cast<PropertyDescriptor>()
                                            where prop.Name == filterDataPath
                                            select prop).SingleOrDefault();
                if (fprop == null)
                    return true;

                object objValue = fprop.GetValue(item);

                if (objValue != null)
                {
                    string value = objValue.ToString();

                    if (string.IsNullOrEmpty(filter))
                        return true;
                    else
                        return value.StartsWith(filter, true, CultureInfo.CurrentCulture);
                }
                else
                    return true;
            };
        }

        #endregion

        #region Grouping

        /// <summary>
        /// Method for Grouping elements
        /// </summary>
        /// <param name="groupColumn"></param>
        internal void PerformGroup(DataGridColumn groupColumn)
        {
            Debug.Assert(groupColumn != null, "GroupColumn should not be null");

            // fire on group event
            DataGridGroupEventArgs eventArgs = new DataGridGroupEventArgs(groupColumn);
            OnGrouping(eventArgs);

            if (Items.NeedsRefresh)
            {
                try
                {
                    Items.Refresh();
                }
                catch (InvalidOperationException invalidOperationException)
                {
                    throw new InvalidOperationException(SR.Get(SRID.DataGrid_ProbableInvalidGroupDescription), invalidOperationException);
                }
            }
        }

        public event DataGridGroupEventHandler Group;

        /// <summary>
        /// Protected method that raises the Group event
        /// </summary>
        /// <param name="eventArgs"></param>
        protected void OnGrouping(DataGridGroupEventArgs eventArgs)
        {
            eventArgs.Handled = false;
            if (Group != null)
            {
                Group(this, eventArgs);
            }

            if (!eventArgs.Handled)
            {
                DefaultGroup(eventArgs.Column);
            }
        }

        /// <summary>
        /// Perfom default group
        /// </summary>
        /// <param name="dataGridColumn"></param>
        private void DefaultGroup(DataGridColumn column)
        {
            ICollectionView collectionView = CollectionViewSource.GetDefaultView(Items);

            string groupMemberPath = column.GroupMemberPath;

            if (string.IsNullOrEmpty(groupMemberPath))
            {
                DataGridBoundColumn boundColumn = column as DataGridBoundColumn;
                if (boundColumn != null)
                {
                    Binding binding = boundColumn.DataFieldBinding as Binding;
                    if (binding != null)
                    {
                        if (!string.IsNullOrEmpty(binding.XPath))
                        {
                            groupMemberPath = binding.XPath;
                        }
                        else if (binding.Path != null)
                        {
                            groupMemberPath = binding.Path.Path;
                        }
                    }
                }
            }

            if (column.Group)
            {
                // add it
                collectionView.GroupDescriptions.Add(new PropertyGroupDescription(groupMemberPath));
            }
            else
            {
                // remove it
                GroupDescription groupDescription = collectionView.GroupDescriptions.Cast<PropertyGroupDescription>().Where(pgd => pgd.PropertyName == groupMemberPath).SingleOrDefault();
                collectionView.GroupDescriptions.Remove(groupDescription);
            }
        }

        #endregion

This is class DataGrid.cs, the are some other classes and some new ones that don't really need any mentioning.

I have 2 questions regarding this:

 - Any ideas on how to make Filter work for FilterMemberPath like "Address.Name"
 - How can I modify the grouping style, I want it to appear like in Microsoft outlook for example

Thank you for your support,
Calin,
Sep 10, 2008 at 3:57 PM
Here is a update to the filtering issue$0$0$0$0$0#region Filtering$0$0$0$0$0        /// <summary>$0$0        /// Dependency property for FilterMemberPath$0$0        /// </summary>$0$0        public static readonly DependencyProperty FilterMemberPathProperty =$0$0            DependencyProperty.Register("FilterMemberPath",$0$0                                        typeof(string),$0$0                                        typeof(DataGridColumn),$0$0                                        new FrameworkPropertyMetadata(String.Empty));$0$0$0$0$0        /// <summary>$0$0        /// The property which the determines the member to be filtered upon$0$0        /// </summary>$0$0        public string FilterMemberPath$0$0        {$0$0            get { return (string)GetValue(FilterMemberPathProperty); }$0$0            set { SetValue(FilterMemberPathProperty, value); }$0$0        }$0$0$0$0$0        /// <summary>$0$0        /// Dependecy property for FilterProperty$0$0        /// </summary>$0$0        public static readonly DependencyProperty FilterProperty =$0$0            DependencyProperty.Register("Filter", typeof(string), typeof(DataGridColumn),$0$0                                        new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnNotifyFilterPropertyChanged)));$0$0$0$0$0        /// <summary>$0$0        /// Property which determines how data will be filtered$0$0        /// </summary>$0$0        public string Filter$0$0        {$0$0            get { return (string)GetValue(FilterProperty); }$0$0            set $0$0            { $0$0                SetValue(FilterProperty, value);$0$0            }$0$0        }$0$0$0$0$0        /// <summary>$0$0        /// Property chnage callback$0$0        /// </summary>$0$0        /// <param name="d"></param>$0$0        /// <param name="e"></param>$0$0        private static void OnNotifyFilterPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)$0$0        {$0$0            DataGridColumn dataGridColumn = d as DataGridColumn;$0$0            $0$0            dataGridColumn.DataGridOwner.PerformFilter(dataGridColumn);$0$0        }$0$0$0$0$0        #endregion$0$0