Click here to Skip to main content
15,891,777 members
Articles / Programming Languages / C#

How to mimic Outlook group naming

Rate me:
Please Sign up or sign in to vote.
4.82/5 (6 votes)
14 Apr 2009CPOL1 min read 38.7K   369   35   8
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:

C#
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.

C#
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:

C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder Prometeo Conseil
France France
When leaving the Ales School of Mines, my first employment, as project Manager and Trainer within company P2I Engineering, allowed me, all along these 7 years, developing my sense of contact and growing my technical knwoledge as well in project management as under software development.

It is strong of these experiments that I was then engaged, in 2001, by Symtrax, an international company (London, Boston, Los Angeles, Mumbaï, Nimes), publisher of software dedicated to analysis and data distribution. My main functions, initially, consisted in training the products manager to the project management like to methodology. Then, those quickly evolved to the management of the information system of the company, distributed on its 5 sites.

Then I was in charge of the management of the network (Proxy server, Mail servers, Active Directory server, Web servers, ftp - based on Windows (2000 and 2003) Operating Systems as well as Linux (RedHat) and SunOS - Solaris) of these 5 sites.

To manage Symtrax Information System, I set up existing tools (Nagios, Microsoft MOM 2005, SNORT…) and have developed my own solution (a solution for fighting against Spam on our Exchange server (in VB.NET 2005 and C#).

Moreover, I’ve managed the installation and the configuration of Microsoft CRM 3.0 on the Company’s sites.

This work implied a daily communication, in English, with the users of all the sites.

From march 2007 to end of 2008, at Data Health System, I was in charge of a new system that detect people’s fall: Ynolis.

From march 2009, I'm working as Consultant for Prometeo (http://www.prometeo.fr)

Comments and Discussions

 
GeneralCode in vb.net Pin
mounaje210-Dec-10 1:01
mounaje210-Dec-10 1:01 
QuestionHow about collapsing/folding group? Pin
Mamber14-Apr-09 21:19
Mamber14-Apr-09 21:19 
AnswerRe: How about collapsing/folding group? Pin
Crusty Applesniffer14-Apr-09 23:03
Crusty Applesniffer14-Apr-09 23:03 
What I was looking for is not to build a new (another one?) ListView control, but rather give an easy way to get the name of a group based on its date.

In fact, I think you can use the Lee Paul Alexander's "Outlook Style Grouped List Control" control.

Or you could use this basic control that inherits of the ListView Control.

C#
class CollapsibleGroupsListview : ListView
{
	public enum GroupState
	{
		COLLAPSIBLE = 8,
		COLLAPSED = 1,
		EXPANDED = 0
	}

	[StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
	public struct LVGROUP
	{
		public int cbSize;
		public int mask;
		[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)]
		public string pszHeader;
		public int cchHeader;

		[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)]
		public string pszFooter;
		public int cchFooter;

		public int iGroupId;

		public int stateMask;

		public int state;
		public int uAlign;
	}

	private bool hasCollapsibleGroup=true;

	[Browsable(true)]
	[EditorBrowsable(EditorBrowsableState.Always)]
	[Category("Appearance")]
	[Description("Set or Get the expand/collapse feature availability for all the groups in the listview.")]
	public bool HasCollapsibleGroups
	{
		get { return hasCollapsibleGroup; }
		set { hasCollapsibleGroup = value;}
	}

	[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
	protected override void WndProc(ref Message m)
	{
		// in order to not catch the click in the expand/collapse icon
		if (m.Msg == 0x202 /*WM_LBUTTONUP*/)
			base.DefWndProc(ref m);


		if (m.Msg == 0x1000 + 145) // LVM_INSERTGROUP     = LVM_FIRST + 145;
		{
			// Add the collapsible feature id needed
			if (hasCollapsibleGroup)
			{
				LVGROUP group = (LVGROUP) Marshal.PtrToStructure(m.LParam, typeof (LVGROUP));
				group.state = (int) GroupState.COLLAPSIBLE; // LVGS_COLLAPSIBLE 
				group.mask = group.mask ^ 4; // LVGF_STATE 
				Marshal.StructureToPtr(group, m.LParam, true);
			}
		}

		base.WndProc(ref m);
	}
}


modified on Wednesday, April 15, 2009 10:59 AM : Add a sample class


-:: Crusty Applesniffer ::-
GeneralRe: How about collapsing/folding group? Pin
Mamber15-Apr-09 23:12
Mamber15-Apr-09 23:12 
GeneralRe: How about collapsing/folding group? Pin
sameh_serag12-Aug-09 22:35
sameh_serag12-Aug-09 22:35 
GeneralRe: How about collapsing/folding group? Pin
Crusty Applesniffer13-Aug-09 2:36
Crusty Applesniffer13-Aug-09 2:36 
GeneralMy vote of 4 Pin
xliqz14-Apr-09 9:29
xliqz14-Apr-09 9:29 
GeneralRe: My vote of 4 Pin
Crusty Applesniffer14-Apr-09 19:26
Crusty Applesniffer14-Apr-09 19:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.