Solution : Supporting N Level binding with JibGrid for Data and Filter,Hiding filter rows,Date Time filtering, Grouping for Nlevel

Jul 13, 2012 at 10:40 AM

 

We were able to solve the limitation of JibGrid to support N Level data for both data and filters. I know its not a clean solution but it works and we are refining it.
These are the steps:
1. Replace ResetFilterValues function in ColumnFilterControl.xaml.cs with the code below.
/// <summary>
        /// ResetFilterValues is called when the column is bound ColumnFilterHeader
        /// </summary>
        /// <param name="filterColumnInfo">Information about the column binding object</param>
        internal void ResetFilterValues(FilterColumnInfo filterColumnInfo)
        {
            this.Visibility = System.Windows.Visibility.Collapsed;
            if (Column != null)
            {
                foreach (var i in DistinctPropertyValues.Where(i => i.IsChecked))
                    i.IsChecked = false;
                DistinctPropertyValues.Clear();
                FilterText = string.Empty;
                _boundColumnPropertyAccessor = null;
                FilterColumnInfo = filterColumnInfo;

                if (FilterColumnInfo.PropertyPath.Length > 0)
                {
                    this.Visibility = System.Windows.Visibility.Visible;
                    ParameterExpression arg = System.Linq.Expressions.Expression.Parameter(typeof(object), "x");
                    System.Linq.Expressions.Expression expr = System.Linq.Expressions.Expression.Convert(arg, Grid.FilterType);
                    
                    //KT: Enabling the Grid to have a binding till Nth Level
                    if (filterColumnInfo.PropertyPath.Contains("."))
                    {
                        int propIncrementor = 0;
                        string[] propArray = filterColumnInfo.PropertyPath.Split(new char[] { '.' });
                      
                        while(propIncrementor < propArray.Length-1)
                        {
                            FilterColumnInfo.PropertyPath = propArray[propIncrementor];
                            Grid.FilterType = expr.Type;
                            expr = System.Linq.Expressions.Expression.Property(expr, Grid.FilterType, propArray[propIncrementor]);
                            propIncrementor++;
                        }
                    }
                    else  
                         expr = System.Linq.Expressions.Expression.Property(expr, Grid.FilterType, FilterColumnInfo.PropertyPath);
                    
                    System.Linq.Expressions.Expression conversion = System.Linq.Expressions.Expression.Convert(expr, typeof(object));
                    _boundColumnPropertyAccessor = System.Linq.Expressions.Expression.Lambda<Func<object, object>>(conversion, arg).Compile();
                }
                else
                {
                    this.Visibility = System.Windows.Visibility.Collapsed;
                }
                ConfigureFilterOptions();
            }
        }

 

2. Replace the function GenerateFilterPredicate with the one below

 

 /// <summary>
        /// This method creates the predicate for the given operation and text
        /// </summary>
        /// <param name="propertyName">The property which the header column is bound to</param>
        /// <param name="filterValue">The value for the predicate.</param>
        /// <param name="objType">The object type of the grid itemsource</param>
        /// <param name="propType">They type for the property</param>
        /// <param name="filterItem">The type of filter (i.e. Contains, Equals...)</param>
        /// <returns>The predicate</returns>
        protected Predicate<object> GenerateFilterPredicate(string propertyName, string filterValue, Type objType, Type propType, FilterOperationItem filterItem)
        {
            ParameterExpression objParam = System.Linq.Expressions.Expression.Parameter(typeof(object), "x");
            UnaryExpression param = System.Linq.Expressions.Expression.TypeAs(objParam, objType);
            System.Linq.Expressions.MemberExpression prop = null;
            if (propertyName.Contains("."))
            {
                string[] propNameArray = propertyName.Split(new char[] { '.' });
                int propCounter = 0;

                var GetList = this.Grid.OrginalSource as IEnumerable;
                Predicate<object> predicate = null;

                while (propCounter < propNameArray.Length - 1)
                {
                    prop = System.Linq.Expressions.Expression.Property(param, propNameArray[propCounter]);




                    foreach (var props in GetList)
                    {
                        var GetChildProp = props.GetType().GetProperty(propNameArray[propCounter]).GetValue(props, null);
                        var GetChildValue = GetChildProp.GetType().GetProperty(propNameArray[propCounter + 1]).GetValue(GetChildProp, null);

                        if (GetChildValue != null)
                        {
                            var ChildValue = GetChildValue as string;

                            if (HasRecord(ChildValue, filterItem, filterValue))
                            {
                                string[] GetPrimaryKey = GetChildProp.ToString().Split(new char[] { ':' });

                                if (GetPrimaryKey.Length > 1)
                                {

                                    Predicate<object> predicate0 = null;

                                    int ChildPrimaryKey = Convert.ToInt32(GetPrimaryKey[1]);
                                    prop = System.Linq.Expressions.Expression.Property(param, propNameArray[propCounter]);
                                    //filterValue = GetPrimaryKey[1];
                                    var val0 = System.Linq.Expressions.Expression.Constant(GetPrimaryKey[propCounter + 1]);

                                    switch (filterItem.FilterOption)
                                    {
                                        case Enums.FilterOperation.Contains:
                                            predicate0 = ExpressionHelper.GenerateGeneric(prop, val0, propType, objParam, "Contains");
                                            break;
                                        case Enums.FilterOperation.EndsWith:
                                            predicate0 = ExpressionHelper.GenerateGeneric(prop, val0, propType, objParam, "EndsWith");
                                            break;
                                        case Enums.FilterOperation.StartsWith:
                                            predicate0 = ExpressionHelper.GenerateGeneric(prop, val0, propType, objParam, "StartsWith");
                                            break;
                                        case Enums.FilterOperation.Equals:
                                            predicate0 = ExpressionHelper.GenerateEquals(prop, filterValue, propType, objParam);
                                            break;
                                        case Enums.FilterOperation.GreaterThanEqual:
                                            predicate0 = ExpressionHelper.GenerateGreaterThanEqual(prop, filterValue, propType, objParam);
                                            break;
                                        case Enums.FilterOperation.LessThanEqual:
                                            predicate0 = ExpressionHelper.GenerateLessThanEqual(prop, filterValue, propType, objParam);
                                            break;
                                        case Enums.FilterOperation.GreaterThan:
                                            predicate0 = ExpressionHelper.GenerateGreaterThan(prop, filterValue, propType, objParam);
                                            break;
                                        case Enums.FilterOperation.LessThan:
                                            predicate0 = ExpressionHelper.GenerateLessThan(prop, filterValue, propType, objParam);
                                            break;
                                        default:
                                            throw new ArgumentException("Could not decode Search Mode.  Did you add a new value to the enum, or send in Unknown?");
                                    }

                                    if (predicate == null)
                                        predicate = predicate0;
                                    else
                                        predicate = predicate.Or(predicate0);
                                }


                            }
                            else
                            {
                                Predicate<object> predicate0 = null;

                                prop = System.Linq.Expressions.Expression.Property(param, propNameArray[0]);
                                var val0 = System.Linq.Expressions.Expression.Constant("-999");

                                predicate0 = ExpressionHelper.GenerateGeneric(prop, val0, propType, objParam, "Contains");


                                if (predicate == null)
                                    predicate = predicate0;
                                else
                                    predicate = predicate.Or(predicate0);
                            }

                            
                        }

                        
                    }
                    propCounter++;
                }
                return predicate;

            }
            else
                prop = System.Linq.Expressions.Expression.Property(param, propertyName);

            var val = System.Linq.Expressions.Expression.Constant(filterValue);

            switch (filterItem.FilterOption)
            {
                case Enums.FilterOperation.Contains:
                    return ExpressionHelper.GenerateGeneric(prop, val, propType, objParam, "Contains");
                case Enums.FilterOperation.EndsWith:
                    return ExpressionHelper.GenerateGeneric(prop, val, propType, objParam, "EndsWith");
                case Enums.FilterOperation.StartsWith:
                    return ExpressionHelper.GenerateGeneric(prop, val, propType, objParam, "StartsWith");
                case Enums.FilterOperation.Equals:
                    return ExpressionHelper.GenerateEquals(prop, filterValue, propType, objParam);
                case Enums.FilterOperation.GreaterThanEqual:
                    return ExpressionHelper.GenerateGreaterThanEqual(prop, filterValue, propType, objParam);
                case Enums.FilterOperation.LessThanEqual:
                    return ExpressionHelper.GenerateLessThanEqual(prop, filterValue, propType, objParam);
                case Enums.FilterOperation.GreaterThan:
                    return ExpressionHelper.GenerateGreaterThan(prop, filterValue, propType, objParam);
                case Enums.FilterOperation.LessThan:
                    return ExpressionHelper.GenerateLessThan(prop, filterValue, propType, objParam);
                default:
                    throw new ArgumentException("Could not decode Search Mode.  Did you add a new value to the enum, or send in Unknown?");
            }

        }

 

3.Add this function :

 

        private bool HasRecord(string value, FilterOperationItem filterItem, string filterValue)
        {
            bool blnHasRecord = false;
            var strValue = value.ToUpper();
            var compareValue = filterValue.ToUpper();


            switch (filterItem.FilterOption)
            {
                case Enums.FilterOperation.Contains:
                    if (strValue.Contains(compareValue)) blnHasRecord = true;
                    break;
                case Enums.FilterOperation.EndsWith:
                    if (strValue.EndsWith(compareValue)) blnHasRecord = true;
                    break;
                case Enums.FilterOperation.StartsWith:
                    if (strValue.StartsWith(compareValue)) blnHasRecord = true;
                    break;
                case Enums.FilterOperation.Equals:
                    if (strValue.Equals(compareValue)) blnHasRecord = true;
                    break;
                default:
                    blnHasRecord = false;
                    break;
            }

            return blnHasRecord;
        }

 

4.  Replace the function cbDistinctProperties_DropDownOpened with the one below. You will see some unclean code for InvalidCastException but thats there only for invalid cast. We couldnt find a better way to do this.

 

//In order to make the grid more performant (sp?) we shouldn't load the distinct value list until the user wants to use it.
        //this method fires before we show the distinct options.  In this method we use the property accessor and get the distinct list.
        private void cbDistinctProperties_DropDownOpened(object sender, EventArgs e)
        {
            if (_boundColumnPropertyAccessor != null)
            {
                if (DistinctPropertyValues.Count == 0)
                {
                    List<object> result = new List<object>();
                    foreach (var i in Grid.OrginalSource)
                    {
                        try
                        {
                            object value = _boundColumnPropertyAccessor(i);
                            if (value != null)
                                if (result.Where(o => o.ToString() == value.ToString()).Count() == 0)
                                    result.Add(value);
                        }
                        catch (InvalidCastException)
                        {

                            object value = null;
                            foreach (var list in this.ChildEntity)
                            {
                                var GetChildProp = i.GetType().GetProperty(list).GetValue(i, null);
                                try
                                {

                                    value = _boundColumnPropertyAccessor(GetChildProp);
                                    break;
                                }
                                catch (InvalidCastException)
                                {
                                    //Leave blank 
                                }
                                catch (Exception)
                                {

                                }
                            }
                            if (value != null)
                                if (result.Where(o => o.ToString() == value.ToString()).Count() == 0)
                                    result.Add(value);
                        }
                        catch (Exception)
                        {
                            //do logging here.
                        }

                    }
                    //should we throw an exception if we can't order the items?  prob not.
                    try
                    {
                        result.Sort();
                    }
                    catch
                    {
                        if (System.Diagnostics.Debugger.IsLogging())
                            System.Diagnostics.Debugger.Log(0, "Warning", "There is no default compare set for the object type");
                    }
 //Simple helper method which creates the FilterColumnInfo object for a column.  If a binding
        //is defined for the column we use that.  If that fails we fallback to using the SortMemberPath
        private FilterColumnInfo CreateFilterColumnInfo(DataGridColumn column)
        {

            FilterColumnInfo col = new FilterColumnInfo();
            DataGridBoundColumn boundColumn = column as DataGridBoundColumn;
            if (column != null)
            {
                if (boundColumn != null)
                {
                    col.PropertyPath = boundColumn.Binding.Path.Path;
              

                    if (boundColumn.Binding.Path.Path == null)
                    {
                        col.PropertyType = typeof(String);
                    }
                    else
                    {
                        if (FilterType.GetProperty(boundColumn.Binding.Path.Path) != null)
                            col.PropertyType = FilterType.GetProperty(boundColumn.Binding.Path.Path).PropertyType;
                        else
                        {
                            col.PropertyType = boundColumn.Binding.Path.Path.GetType() ;
                        }
                    }
                    col.Converter = boundColumn.Binding.Converter;
                    col.ConverterCultureInfo = boundColumn.Binding.ConverterCulture;
                    col.ConverterParameter = boundColumn.Binding.ConverterParameter;

                }
                else if (column.SortMemberPath.Length > 0)
                {
                    col.PropertyPath = column.SortMemberPath;
                    col.PropertyType = FilterType.GetProperty(column.SortMemberPath).PropertyType;
                }
            }
            return col;
        }

foreach (var obj in result) { var item = new CheckboxComboItem() { Description = GetFormattedValue(obj), Tag = obj, IsChecked = false }; item.PropertyChanged += new PropertyChangedEventHandler(filter_PropertyChanged); DistinctPropertyValues.Add(item); } } } }

 

5. Replace the code for CreateFilterColumnInfo() in JibGrid.xaml.cs 

 

     //Simple helper method which creates the FilterColumnInfo object for a column.  If a binding
        //is defined for the column we use that.  If that fails we fallback to using the SortMemberPath
        private FilterColumnInfo CreateFilterColumnInfo(DataGridColumn column)
        {

            FilterColumnInfo col = new FilterColumnInfo();
            DataGridBoundColumn boundColumn = column as DataGridBoundColumn;
            if (column != null)
            {
                if (boundColumn != null)
                {
                    col.PropertyPath = boundColumn.Binding.Path.Path;
              

                    if (boundColumn.Binding.Path.Path == null)
                    {
                        col.PropertyType = typeof(String);
                    }
                    else
                    {
                        if (FilterType.GetProperty(boundColumn.Binding.Path.Path) != null)
                            col.PropertyType = FilterType.GetProperty(boundColumn.Binding.Path.Path).PropertyType;
                        else
                        {
                            col.PropertyType = boundColumn.Binding.Path.Path.GetType() ;
                        }
                    }
                    col.Converter = boundColumn.Binding.Converter;
                    col.ConverterCultureInfo = boundColumn.Binding.ConverterCulture;
                    col.ConverterParameter = boundColumn.Binding.ConverterParameter;

                }
                else if (column.SortMemberPath.Length > 0)
                {
                    col.PropertyPath = column.SortMemberPath;
                    col.PropertyType = FilterType.GetProperty(column.SortMemberPath).PropertyType;
                }
            }
            return col;
        }

 

 

6. For Hiding and unhiding filter rows and for DateTime filtering can be handled in the way defined below:

  • Add an enum in the same namespace  for filtering and hiding and unhiding :

 

  public class Enums
    {
        public enum FilterOperation
        {
            Unknown,
            Contains,
            Equals,
            StartsWith,
            EndsWith,
            GreaterThanEqual,
            LessThanEqual,
            GreaterThan,
            LessThan
        }
        public enum ColumnOption
        {
            Unknown = 0,
            AddGrouping,
            RemoveGrouping,
            PinColumn,
            UnpinColumn,
            HideFilter,
            UnhideFilter
        }
    }
  • Inside the ColumnOptionControl class in the file ColumnOptionControl.xaml.cs add following code:
 ColumnOptionItem _hideFilter = new ColumnOptionItem(Enums.ColumnOption.HideFilter, "Hide Filter", "/Images/Hide.png");
 ColumnOptionItem _unhideFilter = new ColumnOptionItem(Enums.ColumnOption.UnhideFilter, "Unhide Filter", "/Images/Unhide.png");
  • Replace the function SetOptions() in ColumnOptionControl.xaml.cs file

 

 

 private void SetOptions()
        {
            ColumnOptions.Clear();
            if (CanPin)
            {
                if (IsPinned)
                    ColumnOptions.Add(_removePin);
                else
                    ColumnOptions.Add(_addPin);
            }

            if (CanHide)
            {
                if (IsHided)
                    ColumnOptions.Add(_unhideFilter);
                else
                    ColumnOptions.Add(_hideFilter);
            }

            if (CanGroup)
            {
                if (IsGrouped)
                    ColumnOptions.Add(_removeGroup);
                else
                    ColumnOptions.Add(_addGroup);
            }
            if (!CanGroup && !CanPin)
                this.Visibility = System.Windows.Visibility.Collapsed;
        }
  • Replace the function ColumnOptionControl :

 

 public ColumnOptionControl()
        {
            ColumnOptions = new ObservableCollection<ColumnOptionItem>();
            InitializeComponent();
            ColumnOptions.Add(_addPin);
            ColumnOptions.Add(_addGroup);
            ColumnOptions.Add(_hideFilter);
            this.DataContext = this;
            this.Visibility = System.Windows.Visibility.Collapsed;
        }

 

  • In ColumnOptionControl..xaml.cs add this property

 

       private bool _IsHidden;
        public bool IsHidden
        {
            get { return _IsHidden; }
            set
            {
                if (value != _IsHidden)
                {
                    _IsHidden = value;
                    OnPropertyChanged("IsHidden");
                    SetOptions();
                }
            }
        }
  • In the JibGrid.Xaml.cs replace the function optionCtrl_PropertyChanged():

 

   //If the user selects a column option.  We need to perform the operation
        private void optionCtrl_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            isContextMenuEvent = true;
            var optionCtrl = sender as ColumnOptionControl;
            if (e.PropertyName == "SelectedColumnOptionItem")
            {
                switch (optionCtrl.SelectedColumnOptionItem.ColumnOption)
                {
                    case Enums.ColumnOption.AddGrouping:
                        optionCtrl.IsGrouped = true;
                        PagedCollectionView v = this.ItemsSource as PagedCollectionView;
                        PropertyGroupDescription newGroup = new PropertyGroupDescription(optionCtrl.FilterColumnInfo.PropertyPath, optionCtrl.FilterColumnInfo.Converter);
                        ColumnGroups.Add(newGroup);
                        v.GroupDescriptions.Add(newGroup);
                        break;
                    case Enums.ColumnOption.RemoveGrouping:
                        optionCtrl.IsGrouped = false;
                        PagedCollectionView view = this.ItemsSource as PagedCollectionView;
                        PropertyGroupDescription group = ColumnGroups.Where(c => c.PropertyName == optionCtrl.FilterColumnInfo.PropertyPath).FirstOrDefault();
                        if (group != null)
                        {
                            ColumnGroups.Remove(group);
                            view.GroupDescriptions.Remove(group);
                        }
                        break;
                    case Enums.ColumnOption.PinColumn:
                        optionCtrl.IsPinned = true;
                        int frozenCount = this.FrozenColumnCount;
                        if (optionCtrl.Column.DisplayIndex >= this.FrozenColumnCount)
                            frozenCount++;
                        optionCtrl.Column.DisplayIndex = 0;
                        this.FrozenColumnCount = frozenCount;
                        break;
                    case Enums.ColumnOption.UnpinColumn:
                        this.IsHideControl = false;
                        optionCtrl.IsPinned = false;
                        optionCtrl.Column.DisplayIndex = this.FrozenColumnCount - 1;
                        this.FrozenColumnCount = this.FrozenColumnCount - 1;
                        break;
                    case Enums.ColumnOption.HideFilter:
                        this.IsHideControl = true;
                        optionCtrl.IsHided = true;
                        foreach (var header in this.FilterHeaders)
                        {
                            header.Height = 0;
                        }
                        break;
                    case Enums.ColumnOption.UnhideFilter:
                        optionCtrl.IsHided = false;
                        foreach (var header in this.FilterHeaders)
                        {
                            header.Height = 35;
                        }
                        break;
                }
            }
        }

  • Replace the whole class to support DateTime Filtering . Some one can enhance it to associate the Date selection control too.

   public class TypeHelper
    {
        public static object ValueConvertor(Type type, string value)
        {

            if (type == typeof(byte) || type == typeof(byte?))
            {
                byte x;
                if (byte.TryParse(value, out x))
                    return x;
                else
                    return null;
            }
            else if (type == typeof(sbyte) || type == typeof(sbyte?))
            {
                sbyte x;
                if (sbyte.TryParse(value, out x))
                    return x;
                else
                    return null;
            }
            else if (type == typeof(short) || type == typeof(short?))
            {
                short x;
                if (short.TryParse(value, out x))
                    return x;
                else
                    return null;
            }
            else if (type == typeof(ushort) || type == typeof(ushort?))
            {
                ushort x;
                if (ushort.TryParse(value, out x))
                    return x;
                else
                    return null;
            }
            else if (type == typeof(int) || type == typeof(int?))
            {
                int x;
                if (int.TryParse(value, out x))
                    return x;
                else
                    return null;
            }
            else if (type == typeof(uint) || type == typeof(uint?))
            {
                uint x;
                if (uint.TryParse(value, out x))
                    return x;
                else
                    return null;
            }
            else if (type == typeof(long) || type == typeof(long?))
            {
                long x;
                if (long.TryParse(value, out x))
                    return x;
                else
                    return null;
            }
            else if (type == typeof(ulong) || type == typeof(ulong?))
            {
                ulong x;
                if (ulong.TryParse(value, out x))
                    return x;
                else
                    return null;
            }
            else if (type == typeof(float) || type == typeof(float?))
            {
                float x;
                if (float.TryParse(value, out x))
                    return x;
                else
                    return null;
            }
            else if (type == typeof(double) || type == typeof(double?))
            {
                double x;
                if (double.TryParse(value, out x))
                    return x;
                else
                    return null;
            }
            else if (type == typeof(decimal) || type == typeof(decimal?))
            {
                decimal x;
                if (decimal.TryParse(value, out x))
                    return x;
                else
                    return null;
            }
            else if (type == typeof(char) || type == typeof(char?))
            {
                char x;
                if (char.TryParse(value, out x))
                    return x;
                else
                    return null;
            }

            else if (type == typeof(DateTime) || type == typeof(DateTime?))
            {
                DateTime x;
                if (DateTime.TryParse(value, out x))
                    return x;
                else
                    return null;
            }

            return null;
        }

        public static bool IsValueType(Type type)
        {
            return type == typeof(byte) ||
                    type == typeof(sbyte) ||
                    type == typeof(short) ||
                    type == typeof(ushort) ||
                    type == typeof(int) ||
                    type == typeof(uint) ||
                    type == typeof(long) ||
                    type == typeof(ulong) ||
                    type == typeof(float) ||
                    type == typeof(double) ||
                    type == typeof(decimal) ||
                     type == typeof(bool) ||
                    type == typeof(char) ||
                    type == typeof(DateTime);
        }

        public static bool IsNullable(Type type)
        {
            return type != typeof(byte) &&
                type != typeof(sbyte) &&
                type != typeof(short) &&
                type != typeof(ushort) &&
                type != typeof(int) &&
                type != typeof(uint) &&
                type != typeof(long) &&
                type != typeof(ulong) &&
                type != typeof(float) &&
                type != typeof(double) &&
                type != typeof(decimal) &&
                type != typeof(char) &&
                type != typeof(bool) &&
                type != typeof(Single) &&
                type != typeof(DateTime);
        }

        public static bool IsNumbericType(Type p)
        {
            bool result = false;
            result = result || p == typeof(int);
            result = result || p == typeof(decimal);
            result = result || p == typeof(float);
            result = result || p == typeof(int?);
            result = result || p == typeof(decimal?);
            result = result || p == typeof(float?);
            return result;
        }

        public static bool IsDateTimeType(Type p)
        {
            bool result = false;
            result = result || p == typeof(DateTime?);
            return result;
        }


        public static bool IsStringType(Type p)
        {
            return !IsNumbericType(p);
        }
    }
  • Replace the function ConfigureFilterOptions() Inside ColumnFilterControl.xaml.cx

 

  /// <summary>
        /// Reset the avl filter operations given the property type.  This is called each time the control is configured by calling ResetFilterValues
        /// </summary>
        private void ConfigureFilterOptions()
        {
            FilterOperations.Clear();

            //if (FilterColumnInfo.PropertyType.Equals(typeof(Nullable<DateTime>)))
            //{ 

            //}

            if (FilterColumnInfo.PropertyType != null)
            {
                if (TypeHelper.IsStringType(FilterColumnInfo.PropertyType) && !(FilterColumnInfo.PropertyType.Equals(typeof(Nullable<DateTime>))))
                {
                    FilterOperations.Add(new FilterOperationItem(Enums.FilterOperation.Contains, "Contains", "/EDITWeb.Client.Generics.Components.Controls;component/Images/Contains.png"));
                    FilterOperations.Add(new FilterOperationItem(Enums.FilterOperation.StartsWith, "Starts With", "/EDITWeb.Client.Generics.Components.Controls;component/Images/StartsWith.png"));
                    FilterOperations.Add(new FilterOperationItem(Enums.FilterOperation.EndsWith, "Ends With", "/EDITWeb.Client.Generics.Components.Controls;component/Images/EndsWith.png"));
                }
                FilterOperations.Add(new FilterOperationItem(Enums.FilterOperation.Equals, "Equals", "/EDITWeb.Client.Generics.Components.Controls;component/Images/Equal.png"));

                if (TypeHelper.IsNumbericType(FilterColumnInfo.PropertyType))
                {
                    FilterOperations.Add(new FilterOperationItem(Enums.FilterOperation.GreaterThan, "Greater Than", "/EDITWeb.Client.Generics.Components.Controls;component/Images/GreaterThan.png"));
                    FilterOperations.Add(new FilterOperationItem(Enums.FilterOperation.GreaterThanEqual, "Greater Than or Equal", "/EDITWeb.Client.Generics.Components.Controls;component/Images/GreaterThanEqual.png"));
                    FilterOperations.Add(new FilterOperationItem(Enums.FilterOperation.LessThan, "Less Than", "/EDITWeb.Client.Generics.Components.Controls;component/Images/LessThan.png"));
                    FilterOperations.Add(new FilterOperationItem(Enums.FilterOperation.LessThanEqual, "Less Than or Equal", "/EDITWeb.Client.Generics.Components.Controls;component/Images/LessThanEqual.png"));
                }

                if (TypeHelper.IsDateTimeType(FilterColumnInfo.PropertyType))
                {
                    FilterOperations.Add(new FilterOperationItem(Enums.FilterOperation.GreaterThan, "Greater Than", "/EDITWeb.Client.Generics.Components.Controls;component/Images/GreaterThan.png"));
                    FilterOperations.Add(new FilterOperationItem(Enums.FilterOperation.GreaterThanEqual, "Greater Than or Equal", "/EDITWeb.Client.Generics.Components.Controls;component/Images/GreaterThanEqual.png"));
                    FilterOperations.Add(new FilterOperationItem(Enums.FilterOperation.LessThan, "Less Than", "/EDITWeb.Client.Generics.Components.Controls;component/Images/LessThan.png"));
                    FilterOperations.Add(new FilterOperationItem(Enums.FilterOperation.LessThanEqual, "Less Than or Equal", "/EDITWeb.Client.Generics.Components.Controls;component/Images/LessThanEqual.png"));
                }

                SelectedFilterOperation = FilterOperations[0];
            }
        }

This should solve most of the problems. Incase somebody refines the code better please let us know.

Kushagra & Hasnul

 

 

 

    
Sep 20, 2012 at 12:52 PM

I have some error when compiling code with yours changes.

Error 1 Using the generic type 'System.Collections.Generic.IEnumerable<T>' requires 1 type arguments

\Jib\Jib.Controls\DataGrid\ColumnFilterControl.xaml.cs 352 58 Jib.Controls

line is: var GetList = this.Grid.OrginalSource as IEnumerable;

 

Error 2 'Jib.Controls.DataGrid.ColumnFilterControl' does not contain a definition for 'ChildEntity' and no extension method 'ChildEntity' accepting a first argument of type 'Jib.Controls.DataGrid.ColumnFilterControl' could be found (are you missing a using directive or an assembly reference?)\Jib\Jib.Controls\DataGrid\ColumnFilterControl.xaml.cs 231 55 Jib.Controls

line is: foreach (var list in this.ChildEntity)

 

Error 2 'Jib.Controls.DataGrid.JibGrid' does not contain a definition for 'IsHideControl' and no extension method 'IsHideControl' accepting a first argument of type 'Jib.Controls.DataGrid.JibGrid' could be found (are you missing a using directive or an assembly reference?)

\Jib\Jib.Controls\DataGrid\JibGrid.xaml.cs 172 30 Jib.Controls

line is: this.IsHideControl = false;

 

Error 5 'Jib.Controls.DataGrid.ColumnOptionControl' does not contain a definition for 'IsHided' and no extension method 'IsHided' accepting a first argument of type 'Jib.Controls.DataGrid.ColumnOptionControl' could be found (are you missing a using directive or an assembly reference?)

\Jib\Jib.Controls\DataGrid\JibGrid.xaml.cs 186 36 Jib.Controls

line is: optionCtrl.IsHided = false;

 

Sep 23, 2012 at 7:33 AM

I am trying to send a complete working source for you. I might upload it on skydrive. But you have to wait till tomorrow

 

-Kushagra 

Sep 23, 2012 at 8:29 AM

Hi ,

I have uploaded the Code on Skydrive. It has all the features listed below:

1.Supporting N Level binding for Data and Filter,

2.Hiding filter rows (You can find this option inside the dropdown of filters)

3.Date Time filtering (It supports Data time filtering if  you have  column for date time)

4.Grouping for Nlevel (Binding and Grouping to N level is supported)

Hope the code helps you. You can find the code here: JibGrid_Edited.rar. I agree the code has some bugs which you need to solve before using it in commercial application. If you are able to improve it .. Please don't mind sharing the code

 

Warm Regards,

Kushagra

tiwari.kushagra@gmail.com

 

Nov 5, 2012 at 7:34 AM

Hello Kushagra,

 

your solution of N Level binding for Data and Filter is generating a lot of expresions, even no needed to be.

 

what you think about this method? in my opinion it is much lighter version....

 /// <summary>
        /// This method creates the predicate for the given operation and text
        /// </summary>
        /// <param name="propertyName">The property which the header column is bound to</param>
        /// <param name="filterValue">The value for the predicate.</param>
        /// <param name="objType">The object type of the grid itemsource</param>
        /// <param name="propType">They type for the property</param>
        /// <param name="filterItem">The type of filter (i.e. Contains, Equals...)</param>
        /// <returns>The predicate</returns>
        protected Predicate<object> GenerateFilterPredicate(string propertyName, string filterValue, Type objType, Type propType, FilterOperationItem filterItem)
        {
            ParameterExpression objParam = System.Linq.Expressions.Expression.Parameter(typeof(object), "x");
            UnaryExpression param = System.Linq.Expressions.Expression.TypeAs(objParam, objType);
            System.Linq.Expressions.MemberExpression prop = null;
            var val = System.Linq.Expressions.Expression.Constant(filterValue);

            if (propertyName.Contains("."))
            {
                string[] propNameArray = propertyName.Split(new char[] { '.' });

                prop = System.Linq.Expressions.Expression.Property(param, propNameArray[0]);

                for (int i = 1; i < propNameArray.Length; i++)
                {
                    prop = System.Linq.Expressions.Expression.Property(prop, propNameArray[i]);
                }

            }
            else
                prop = System.Linq.Expressions.Expression.Property(param, propertyName);
                
                switch (filterItem.FilterOption)
                {
                    case Enums.FilterOperation.Contains:
                        return ExpressionHelper.GenerateGeneric(prop, val, propType, objParam, "Contains");
                    case Enums.FilterOperation.EndsWith:
                        return ExpressionHelper.GenerateGeneric(prop, val, propType, objParam, "EndsWith");
                    case Enums.FilterOperation.StartsWith:
                        return ExpressionHelper.GenerateGeneric(prop, val, propType, objParam, "StartsWith");
                    case Enums.FilterOperation.Equals:
                        return ExpressionHelper.GenerateEquals(prop, filterValue, propType, objParam);
                    case Enums.FilterOperation.GreaterThanEqual:
                        return ExpressionHelper.GenerateGreaterThanEqual(prop, filterValue, propType, objParam);
                    case Enums.FilterOperation.LessThanEqual:
                        return ExpressionHelper.GenerateLessThanEqual(prop, filterValue, propType, objParam);
                    case Enums.FilterOperation.GreaterThan:
                        return ExpressionHelper.GenerateGreaterThan(prop, filterValue, propType, objParam);
                    case Enums.FilterOperation.LessThan:
                        return ExpressionHelper.GenerateLessThan(prop, filterValue, propType, objParam);
                    default:
                        throw new ArgumentException("Could not decode Search Mode.  Did you add a new value to the enum, or send in Unknown?");
                }         

        }

 

Nov 6, 2012 at 7:22 AM

Hi Milan,

 

Great to hear back from you. Yes, your version of function 'GenerateFilterPredicate' would also provide us the desired results. I have tested it and its working fine with the solution. Again, the solution I had provided was in raw format and yes many more optimizations can be done to improve the performance of the application by many folds. I would be uploading another version of JibGrid soon which is even better and lighter than the old solution provided.

 

Warm Regards,

Kushagra 

Nov 7, 2012 at 6:23 AM

Hi Kushagra,

If you have plan to upload a new version. Maybe you should include a microsoft dynamic linq extension.

http://msdn.microsoft.com/en-us/vstudio//bb894665.aspx

i had problem with jbGrid and DomainCollectionView, if you aplly filtering just in the grid and datas are paged, you can filter only current page.

For that reason i had to create a set of functions which generating a string format of filter, then pass it to RIA services query and return new paged, filtered collection. I choosed string format, becouse RIA services have problem if parameter is not a standard serializable variable type.

I created a another depency property which exposing this filter string, then you can easy bind and execute query if filter string has changed.

 

Nov 28, 2012 at 11:23 AM

Hi Milan,

Sorry for the late reply. I would be uploading the new version soon. I apologize for the delay. I would take a note of your point mentioned above and would definitely try to include  microsoft dynamic linq extension.

 

Thanks 

Kushagra

Feb 27, 2014 at 5:23 AM
Hi,

Could you please upload the new version.

Kind regards,
Franky
Aug 29, 2014 at 9:42 AM
Hi,

We used a code similar to it, and added another filtering condition 'Not Contains' it is filtering using Expression.Not(Expression exp); method, it is working fine for single selection but when comes to multiple selection(more than 1) It is not filtering anything. Can anyone please help regarding this.