How to mimic the Outlook group name style ?

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,…”

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) &amp;&amp; (-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 for every item the Group property as follow:

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 …
Outlook Groupname sample

PS: as I am French, weeks start on monday, sorry 😉

Leave a comment

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.