Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to mimic Outlook group naming

0.00/5 (No votes)
14 Apr 2009 1  
How to group items in a listview based on a date.

Introduction

Recently, I had to sort items in my listview. OK, I heard you, "nothing difficult doing that". But, I also had to group them as Outlook does. I mean "according to the date, today items, yesterday items, tomorrow items, next month items,...".

Using the Code

First of all, we have to define the label for each group:

private void Form1_Load(object sender, EventArgs e)
{
  string[] groupName = {"Older",
       "Last month", "4 weeks ago", "3 weeks ago", 
       "2 weeks ago", "Last week",
       "Monday", "Tuesday", "Wednesday", 
       "Thursday", "Friday", "Saturday", "Sunday",
       "Yesterday",
       "Today",
       "Tomorrow", 
       "Monday", "Tuesday", "Wednesday", 
       "Thursday", "Friday", "Saturday", "Sunday", 
       "Next week", "In 2 weeks", 
       "In 3 weeks", "In 4 weeks", "Next month", 
       "Newer"};

  // populate the group list
  foreach(string group in groupName)
    listView1.Groups.Add(new ListViewGroup(group));
}

Then, we have to define what group an item belongs to according to the current date and the item's date.

internal static int GetDateTimeGroupIndex(DateTime dtRef, DateTime dtSource)
{
  // Because week starts on Monday in France
  int dtWeekDay = (Convert.ToInt32(dtSource.DayOfWeek) + 6) % 7;
  int dtRefWeekDay = (Convert.ToInt32(dtRef.DayOfWeek) + 6) % 7;

  int ts = (dtRef.Date - dtSource.Date).Days;

  if (ts == 0)
    return 0;  // same day
  if (ts == 1)
    return -1; // day before

  if (ts == -1)
    return 1; // day after

  // same week 
  if ((ts > 1) && (ts <= dtRefWeekDay))
    return dtWeekDay - 8;

  if ((-ts > 1) && (-ts <= 6 - dtRefWeekDay))
    return dtWeekDay + 2;

  // previous / next weeks
  for (int nIdx = 0; nIdx <= 3; nIdx++)
  {
    if ((ts > dtRefWeekDay + nIdx * 7) && 
        (ts <= dtRefWeekDay + (nIdx + 1) * 7))
      if (dtRef.Month == dtSource.Month)
       return -(9 + nIdx);
      else
        return -13;
    if ((-ts > 6 - dtRefWeekDay + nIdx * 7) && 
        (-ts <= 6 - dtRefWeekDay + (nIdx + 1) * 7))
      if (dtRef.Month == dtSource.Month)
       return (9 + nIdx);
      else
        return 13;
  } 

  if (Math.Abs(dtSource.Month - dtRef.Month) == 1) 
   return Math.Sign(ts) * (-13);
 return Math.Sign(ts) * (-14);
}

Finally, we have to set the Group property for every item as follows:

DateTime dtDate = DateTime.Now.AddMonths(-2);
while(dtDate < DateTime.Now.AddMonths(2))
{
  ListViewItem item = new ListViewItem("Item " + 
               dtDate.Date.ToString("dd/MM/yyyy"));
  item.Group = listView1.Groups[GetDateTimeGroupIndex(DateTime.Now, dtDate) + 14];
  listView1.Items.Add(item);
  dtDate = dtDate.AddDays(1);
}

And the result is ...

Points of Interest

The thing to note is that groups are displayed in the same order they are created; that is why I create them from older to newer and why I repeat the day name: the first time for when the item is older than today (if it is Friday, items from last Wednesday will belong to the group labeled "Wednesday" - the first one, and if it is Monday, items from next Wednesday will belong to the group labeled "Wednesday" too, but the second one).

Then, when the listview is sorted, groups are sorted, and in each group, items are sorted too.

History

  • 04/14/2009: First submission.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here