FlexGrid for WPF | ComponentOne
Features / Data Grouping / Group Data using FlexGridGroupPanel / Custom Group Converters
In This Topic
    Custom Group Converters
    In This Topic

    Besides providing support to group data on explicit columns, FlexGrid also supports creating custom group converters to group data based on some categories. For example, grouping data by some arbitrary order date or price point, or both can be vague. However, if the column price points can be further categorized into sub groups such as high, moderate, low, etc., then data organization becomes more meaningful. The FlexGridGroupPanel control enables users in realizing such grouping requirements by creating sub-groups or defining range.

    The image given below illustrates custom data grouping on the basis of price range.

    Custom Grouping

    To create custom group converters in code

    1. Create a WPF application in Visual Studio.
    2. Drag FlexGrid control onto the XAML designer.
    3. Add a FlexGridGroupPanel above the FlexGrid control using the following XAML code.
      XAML
      Copy Code
      <Grid>
          <Grid.RowDefinitions>
              <RowDefinition Height="Auto"/>
              <RowDefinition />
          </Grid.RowDefinitions>                          
                <c1:C1FlexGridGroupPanel 
                   x:Name="_groupPanelCustomGrouping" Grid.Row="0" Background="WhiteSmoke"
                   WatermarkText="Drag column headers here to create groups."
                   MaxGroups="8"
                   HideGroupedColumns="False"
                   DragMarkerColor="#FF5C54"
                   FlexGrid="{Binding ElementName=_flexCustomGrouping}" 
                   PropertyGroupCreated="_groupPanelCustomGrouping_PropertyGroupCreated"/>
                <c1:C1FlexGrid
                   x:Name="_flexCustomGrouping" Grid.Row="1" 
                   TopLeftCellBackground="Bisque"
                   ColumnHeaderBackground="Bisque"
                   RowHeaderBackground="Bisque"
                   GroupRowBackground="LightGoldenrodYellow"
                   RowBackground="White"
                   AlternatingRowBackground="White"/>                      
      </Grid>
      


    4. Add a new class to your project, Products.cs, to display data in the grid.
      C#
      Copy Code
      public class Product : BaseObject
      {
          string _name, _color, _line;
          double _price, _cost;
          DateTime _date;
          bool _discontinued;
      
          static Random _rnd = new Random();
          static string[] _names = "Macko|Surfair|Pocohey|Studeby".Split('|');
          static string[] _lines = "Computers|Washers|Stoves|Cars".Split('|');
          static string[] _colors = "Red|Green|Blue|White".Split('|');
      
          public Product()
          {
              Name = PickOne(_names);
              Line = PickOne(_lines);
              Color = PickOne(_colors);
              Price = 30 + _rnd.NextDouble() * 1000;
              Cost = 3 + _rnd.NextDouble() * 300;
              Discontinued = _rnd.NextDouble() < .2;
              Introduced = DateTime.Today.AddDays(_rnd.Next(-600, 0));
          }
          string PickOne(string[] options)
          {
              return options[_rnd.Next() % options.Length];
          }
      
          //[Display(Name = "Name")]
          public string Name
          {
              get { return _name; }
              set { SetProperty("Name", ref _name, value); }
          }
      
          //[Display(Name = "Color")]
          public string Color
          {
              get { return _color; }
              set { SetProperty("Color", ref _color, value); }
          }
      
          //[Display(Name = "Line")]
          public string Line
          {
              get { return _line; }
              set { SetProperty("Line", ref _line, value); }
          }
      
          //[Display(Name = "Price")]
          public double Price
          {
              get { return _price; }
              set { SetProperty("Price", ref _price, value); }
          }
      
          //[Display(Name = "Cost")]
          public double Cost
          {
              get { return _cost; }
              set { SetProperty("Cost", ref _cost, value); }
          }
      
          //[Display(Name = "Introduced")]
          public DateTime Introduced
          {
              get { return _date; }
              set { SetProperty("Introduced", ref _date, value); }
          }
      
          //[Display(Name = "Discontinued")]
          public bool Discontinued
          {
              get { return _discontinued; }
              set { SetProperty("Discontinued", ref _discontinued, value); }
          }
      }
      
      public class BaseObject : INotifyPropertyChanged, IEditableObject
      {
          protected bool SetProperty<T>(string propName, ref T field, T value)
          {
              if (EqualityComparer<T>.Default.Equals(field, value)) return false;
              field = value;
              OnPropertyChanged(propName);
              return true;
          }
      
          public event PropertyChangedEventHandler PropertyChanged;
          void OnPropertyChanged(string propName)
          {
              OnPropertyChanged(new PropertyChangedEventArgs(propName));
          }
          protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
          {
              if (PropertyChanged != null)
                  PropertyChanged(this, e);
          }       
      
          object _clone = null;
          public void BeginEdit()
          {
              _clone = this.MemberwiseClone();
          }
          public void CancelEdit()
          {
              foreach (var p in this.GetType().GetProperties())
              {
                  var value = p.GetValue(_clone, null);
                  p.SetValue(this, value, null);
              }
          }
          public void EndEdit()
          {
              _clone = null;
          }       
      }
      


    5. Add two classes, AmountGroupConverter.cs and DateTimeGroupConverter.cs, in your project. These classes are simple converters to group double values of the Price and Cost column, and DateTime values of Introduced and Discontinued columns into well-defined ranges.
      public class AmountGroupConverter : IValueConverter
      {
          double _maxValue;
          public AmountGroupConverter(double maxValue)
          {
              _maxValue = maxValue;
          }
          public object Convert(object value, Type targetType, 
              object parameter, System.Globalization.CultureInfo culture)
          {
              var pct = (double)value / _maxValue;
              if (pct < .25) return "Very Low";
              if (pct < .50) return "Low";
              if (pct < .75) return "Moderate";
              return "High";
          }
          public object ConvertBack(object value, Type targetType, 
              object parameter, System.Globalization.CultureInfo culture)
          {
              throw new NotImplementedException();
          }
      }
      
      public class DateTimeGroupConverter : IValueConverter
      {
          public object Convert(object value, Type targetType, 
              object parameter, System.Globalization.CultureInfo culture)
          {
              var list = new List<string>();
              var date = (DateTime)value;
              var today = DateTime.Today;
              if (today.Subtract(date).TotalDays <= 7) list.Add("This week");
              if (date.Year == today.Year && date.Month == today.Month) list.Add("This month");
              if (date.Year == today.Year)
              {
                  list.Add("This year");
              }
              else if (date.Year == today.Year - 1)
              {
                  list.Add("Last year");
              }
              else
              {
                  list.Add("Before last year");
              }
              return list;
          }
          public object ConvertBack(object value, Type targetType, 
              object parameter, System.Globalization.CultureInfo culture)
          {
              throw new NotImplementedException();
          }
      }
      


    6. Switch to the MainWindow.cs file and add the following code to add data in the FlexGrid.
      C#
      Copy Code
      // create a data source
      var list = new List<Product>();
      for (int i = 0; i < 200; i++)
      {
          list.Add(new Product());
      }
      // assign the data source to grid
      var cvs = new CollectionViewSource() { Source = list };
      _flexCustomGrouping.ItemsSource = cvs.View;
      


    7. Add the following code in the handler of the PropertyGroupCreated event to assign custom converters to different columns in the data source.
      C#
      Copy Code
      private void _groupPanelCustomGrouping_PropertyGroupCreated
          (object sender, C1.WPF.FlexGrid.PropertyGroupCreatedEventArgs e)
      {
          var pgd = e.PropertyGroupDescription;
          switch (pgd.PropertyName)
          {
              case "Introduced":
                  pgd.Converter = new DateTimeGroupConverter();
                  break;
              case "Discontinued":
                  pgd.Converter = new DateTimeGroupConverter();
                  break;
              case "Price":
                  pgd.Converter = new AmountGroupConverter(1000);
                  break;
              case "Cost":
                  pgd.Converter = new AmountGroupConverter(300);
                  break;
          }
      }
      
    See Also