title: XamDataGrid GroupByEvaluator Date Sorting vb.net
body: <p>I've been trying to implement some custom grouping with Infragistics xamDataGrid (Infragistics3.Wpf.DataPresenter.v9.1.Express), and pretty much cribbed the entire bit of code from the <a href="http://help.infragistics.com/Help/Doc/WPF/2011.1/CLR4.0/html/InfragisticsWPF4.DataPresenter.v11.1~Infragistics.Windows.DataPresenter.FieldSettings~GroupByEvaluator.html" rel="nofollow">Infragistics site</a>. I have two different date fields -- Due Date, and Reminder Date -- using GroupByEvaluator. Everything seemed well and good until I tried to add both fields to the GroupByArea.  </p>
  
  <p>What happens is this: the nested field groups according to the date of the parent field as opposed to grouping of the parent field. For example, when I drag the "Due Date" (parent) field to the GroupBy, it'll group these records by Due Date into four categories -- Due Next Year, Due This Year, Past Due, and Not Set. Perfect. But when I drag the "Reminder Date" field (nested) to the GroupBy, I'll find multiple labels of the same "Reminder Date" grouping nested under Due Date "Past Due". </p>
  
  <p>I'm a newbie posting to SO, so I can't post an image. Instead, I'll type one out:</p>
  
  <ul>
  <li><p>Past Due (Due Date)</p>
  
  <ul>
  <li>Not Set (Reminder Date)</li>
  <li>This Month (Reminder Date)  </li>
  <li>Not Set (Reminder Date)  </li>
  <li>Older (Reminder Date) </li>
  <li>Not Set (Reminder Date)  </li>
  <li>etc....</li>
  </ul></li>
  </ul>
  
  <p>With each subsequent nested grouping, the earliest Due Date (value of the parent grouping) is equal to or greater than the greatest Due Date of the previous grouping. It appears as though the "Past Due" collection is sorted by Due Date asc, and it's iterating through each record and creating a new nested group whenever there is a change in the nested label. So after 5 groupByRecords are given the label of "This Month", when the next "Not Set" groupByRecord pops up a new nested label is created instead of continuing to populate the existing one. </p>
  
  <p>I'm having a related issue with sorting, which I suspect is what this entire issue hinges on. If the grid has been sorted according to Due Date, all of the sort by functionality of the other fields are constrained by the Due Dates. For example, sorting by client name will not sort all client name records into ascending or descending. Instead, it will sort, but it sort by Due Date first, and then Name.</p>
  
  <p>Sorry I can't attach an image. Hopefully I explained the issue okay. </p>
  
  <p>Thanks in advance! Code below: </p>
  
  <pre><code> Imports System.Collections.ObjectModel
   Imports Infragistics.Windows.DataPresenter
   Imports System.Windows
   Imports System.Windows.Controls
  
   Partial Public Class ManageEntities
   Public Sub New()
  
      ' This call is required by the designer.
      InitializeComponent()
  
      ' Add any initialization after the InitializeComponent() call.
      Me.InitializeGroupByGrid()
   End Sub
  
   #Region "CustomGrouping"
         'http://help.infragistics.com/Help/Doc/WPF/2012.2/CLR4.0/html/InfragisticsWPF4.DataPresenter.v12.2~Infragistics.Windows.DataPresenter.IGroupByEvaluator.html 
  Private Sub InitializeGroupByGrid()
      For Each f In Me.SelectorGrid.FieldLayouts(0).Fields
          If f.Name = "Form1DueDate" OrElse f.Name = "Form1LastReminderDate" Then
              f.Settings.GroupByEvaluator = New CustomDateTimeEvaluator
  
              ' group by the data field
              Dim fsd As FieldSortDescription = New FieldSortDescription()
              fsd.Field = f
              fsd.Direction = System.ComponentModel.ListSortDirection.Descending
  
              Me.SelectorGrid.FieldLayouts(0).SortedFields.Add(fsd)
          End If
      Next
  End Sub
   #End Region
  
  End Class
  
   #Region "CustomDateTimeEvaluator"
  
   '//20150918 - From infragistics: http://help.infragistics.com/Help/Doc/WPF/2013.1/CLR4.0/html/InfragisticsWPF4.DataPresenter.v13.1~Infragistics.Windows.DataPresenter.IGroupByEvaluator.html
  Friend Class CustomDateTimeEvaluator
  Implements IGroupByEvaluator
  
  Private Const NotSet As String = "Not Set"
  Private Const PastDue As String = "Past Due"
  Private Const DueThisYear As String = "Due This Year"
  Private Const DueNextYear As String = "Due Next Year"
  Private Const RemindThisMonth As String = "This Month"
  Private Const RemindLastMonth As String = "Last Month"
  Private Const Older As String = "Older"
  
  Dim targetDate As DateTime = Nothing
  
  Public Function DoesGroupContainRecord(ByVal groupByRecord As GroupByRecord, ByVal record As DataRecord) As Boolean Implements IGroupByEvaluator.DoesGroupContainRecord
      Dim cellValue As Object = record.GetCellValue(groupByRecord.GroupByField)
      Dim desc As String = groupByRecord.Description
  
      ' handle null values specially
      If cellValue Is Nothing Or TypeOf cellValue Is DBNull Then
          Return desc = NotSet
      End If
  
      ' if the value is not a date time, just group them together
      If TypeOf cellValue Is DateTime = False Then
          Return True
      End If
  
      Return desc = GetDateLabel(CType(cellValue, DateTime), groupByRecord.GroupByField.Name)
  End Function
  
  Public Function GetGroupByValue(ByVal groupByRecord As GroupByRecord, ByVal record As DataRecord) As Object Implements IGroupByEvaluator.GetGroupByValue
      Dim cellValue As Object = record.GetCellValue(groupByRecord.GroupByField)
      Dim desc As String = String.Empty
      Dim targetDate As DateTime = DateTime.MinValue
  
      If cellValue Is Nothing Or TypeOf cellValue Is DBNull Then
          desc = NotSet
      ElseIf TypeOf cellValue Is DateTime Then
          targetDate = CType(cellValue, DateTime)
          desc = GetDateLabel(targetDate, groupByRecord.GroupByField.Name)
      End If
  
      groupByRecord.Description = desc
      Return targetDate
  End Function
  
  Public ReadOnly Property SortComparer() As System.Collections.IComparer Implements IGroupByEvaluator.SortComparer
      Get
          Return Nothing
      End Get
  End Property
  
  Private Function GetDateLabel(ByVal dt As DateTime, ByVal fldName As String) As String
      Dim d As String = NotSet
      Dim comparison As Integer = Nothing
      Dim currentYear As Integer = DatePart(DateInterval.Year, Now)
  
      '//If no date, return NotSet
      If dt.Ticks = 0 Then
          Return d
      End If
  
      '//Group by fieldname name
      If fldName.ToLower = "form1duedate" Then
          '//Past Due includes any records where the Form 1 Due Date is less than July 1st of the current year
          Dim cDDate As New DateTime(currentYear, 7, 1)
  
          comparison = dt.Date.CompareTo(cDDate.Date)
  
          If comparison = 0 Then
              d = DueThisYear
          ElseIf comparison &lt; 0 Then
              d = PastDue
          ElseIf comparison &gt; 0 Then
              d = DueNextYear
          Else
              d = NotSet
          End If
      ElseIf fldName.ToLower = "form1lastreminderdate" Then
          Dim currentMonth As Integer = DatePart(DateInterval.Month, Now)
          Dim olderThanDate As New DateTime(currentYear, currentMonth - 1, 1)
  
          If dt.Date.Year = currentYear AndAlso dt.Date.Month = currentMonth Then
              d = RemindThisMonth
          ElseIf dt.Date.Year = currentYear AndAlso dt.Date.Month = currentMonth - 1 Then
              d = RemindLastMonth
          ElseIf dt.Date &lt; olderThanDate Then
              d = Older
          Else
              d = NotSet
          End If
      End If
  
      Return d
  End Function
  
  End Class
  
  #End Region
  </code></pre>