5,778,647 members and growing! (21,802 online)
Email Password   helpLost your password?
Web Development » Custom Controls » General     Intermediate License: The Apache License, Version 2.0

DayPilot - Building an Outlook-Like Calendar Component for ASP.NET

By Dan Letecky

A good-looking ASP.NET control that shows events visually arranged in a day calendar. Includes design-time support and data binding.
Javascript, C#, HTML, Windows, .NET, Visual Studio, ASP.NET, Dev

Posted: 16 Dec 2005
Updated: 21 Mar 2006
Views: 136,145
Bookmarked: 215 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
89 votes for this Article.
Popularity: 9.20 Rating: 4.72 out of 5
4 votes, 4.5%
1
0 votes, 0.0%
2
4 votes, 4.5%
3
6 votes, 6.7%
4
75 votes, 84.3%
5

Building an Outlook-like calendar component for ASP.NET

The story is simple and you might have already heard it: I needed a component and because I wasn't able to find a good one I decided to write it. I was thinking like this: It would take me two hours to find it, another two hours to understand it and another two hours to customize it. Six hours. In six hours, I should be able to write a simple component by myself.

My project specification was simple.

Features

  • Reusable ASP.NET component for visually showing the events that happened during one day.
  • It must look like Outlook.
  • It must accept a DataTable with a specified structure as a data source.
  • User-defined JavaScript action for double-clicking the item.
  • User-defined JavaScript action for double-clicking the free time.
  • Support for working hours - doesn't show the time outside the working hours unless there is an event.
  • Support for events started before or finish after the current day.
  • Support for overlapping events (two or more events for a particular moment).

Features that are not supported

  • Drag and drop moving
  • Inline editing

In short, no AJAX at the moment. What I need is to show the events arranged and catch the most important events (clicking the event and clicking the free space).

Problem #1: Algorithm for arranging concurrent events

This didn't take too long. After the first hour I had the draft:

  • "Event" class will keep the basic information about the event, like starting and ending time, title, etc.
  • "Day" class will keep all the events for a certain day. It will be able to load the events from a DataTable. Each day can contain zero or more Blocks.
  • "Block" class will contain events that overlap with one another. Each Block contains one or more Columns.
  • "Column" class will contain all the events inside a Block that can be in a single Column.

Let's demonstrate it visually:

The algorithm can be described in the following steps:

  1. Shorten all the Events so that they don't overlap to another day (e.g. if something starts yesterday, let's make it start today at 00:00).
  2. Extend the Events' duration to 30 minutes blocks (we would have problems showing a duration of 5 minutes, 5 seconds - it wouldn't be possible to write any text into a rectangle of such a small height).
  3. Find Blocks:
    • Order all the events by the starting time (primary) and by the ending time in reverse (secondary) - longer events go closer to the left.
    • Iterate through the events - if it overlaps with the previous add it to the current Block; otherwise create a new Block.
  4. Arrange Events into Columns inside a Block (do this for each Block):
    • Find a moment with the most overlaps and count the overlaps. Create that many numbers of Columns.
    • Arrange Events into Columns - find the first free Column from the left and place it there.

Now, we can calculate the position of each Event because we know the Blocks and Columns:

  • Left: (the column number)/(total count of columns for the owner block) in percent.
  • Width: 1/(total count of columns) in percent
  • Top: (starting time)*(hour height)
  • Height: (duration)*(hour height)

Problem #2: Positioning the events using CSS

To show the calendar we need to draw a table with the hour numbers and yellow free cells and then draw another layer on top of the calendar that contains the events. The other "layer" can be created by setting the cascading style:

position: absolute;
top: 20px;
left: 20px;

The position is defined by the "top" and "left" coordinates. These are related to the upper left corner of the document or to the upper left corner of the containing element that has the position defined (if any).

Problem #3: Box size behavior in Firefox/Internet Explorer

The biggest problem while calculating the positions was a major difference between Firefox and Internet Explorer:

  • In Firefox, if you define the width and border (or padding, etc.) the total width of that box will be width + border. Firefox draws the border outside of the box.
  • In Internet Explorer, if you define the width and border the total width will be the width specified. Internet Explorer draws the borders inside the box.

To achieve the same behavior in IE and FF, I had to nest several DIV elements to create borders and padding. The resulting HTML of an event looks like this:

<div onselectstart="return false;" 
  onclick="event.cancelBubble=true;alert('Event ID: 4');"
  onmouseover="this.firstChild.style.backgroundColor='#DCDCDC';
              event.cancelBubble=true;" 
  onmouseout="this.firstChild.style.backgroundColor='white';
             event.cancelBubble=true;" 
  style="-moz-user-select:none;-khtml-user-select:none;
        user-select:none;cursor:pointer;cursor:hand;
        position:absolute;font-family:Tahoma;font-size:8pt;
        white-space:no-wrap;left:0%;top:1;width:100%;height:40;
        background-color:gray;">
    <div title="Breakfest (8:00 AM - 9:00 AM)" 
      style="margin-top:1px;display:block;height:38;
      background-color:white;border-left:1px solid gray;
      border-right:1px solid gray;overflow:hidden;">

        <div style="float:left;width:5px;height:100%;
             background-color:blue;">
        </div>
        <div style="float:left;width:2px;height:100%;"></div>
        <div style="padding:2px;">Breakfest (8:00 AM - 9:00 AM)
        </div>
    </div>
</div>

Problem #4: Firefox treated as a low-level browser

It is a known problem. The symptoms were that the HtmlWriter class that is used to render the HTML of the component automatically translates the DIV elements to TABLE elements and the STYLE attribute contents to (sometimes) the corresponding HTML attributes. This results in different appearance in Internet Explorer and in other browsers.

There are two possible solutions:

The first option was not possible because of the additional configuration required so I had to create several helper classes and write it directly as whole strings.

The final result

Finally, it took me a few days instead of a few hours but now you can share the result with me:

Updates

Please visit the DayPilot site for the updates.

History

  • 3rd February, 2006: DayPilot 1.1
    • New features: Server-side events (postback), improved support for business hours, 12-hour and 24-hour time formats.
  • 2nd January, 2006: DayPilot 1.0.3
    • Fixed: Support for HTML 4.01 Transitional or XHTML 1.0 Transitional.
  • 28th December, 2005: DayPilot 1.0.2
    • Fixed: Design-time preview.
  • 22nd December, 2005: DayPilot 1.0.1
    • Fixed: View state problems.

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0

About the Author

Dan Letecky


My open-source ASP.NET 2.0 controls:

DayPilot - Outlook-like calendar/scheduling control
DayPilot MonthPicker - Light-weight month picker
MenuPilot - Hover context menu

Location: Czech Republic Czech Republic

Other popular Custom Controls articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 72 (Total in Forum: 72) (Refresh)FirstPrevNext
QuestionIntegrate With Real Time Exchange ServermemberClemie3:12 6 May '08  
AnswerRe: Integrate With Real Time Exchange ServermemberDan Letecky4:36 13 May '08  
GeneralLicense questionmemberarcb21:08 17 Jan '08  
AnswerRe: License questionmemberDan Letecky10:02 18 Jan '08  
GeneralFor Windows Formsmembercan kayacan0:53 28 Sep '07  
GeneralRe: For Windows FormsmemberDan Letecky6:56 28 Sep '07  
GeneralExtractingmemberClaudeX0:40 7 Jun '07  
GeneralRe: ExtractingmemberDan Letecky22:56 8 Jun '07  
Generalfree?memberKhinLLK0:47 25 Apr '07  
GeneralRe: free?memberDan Letecky3:08 25 Apr '07  
GeneralLicense questionmemberPhilBaker4:43 31 Jan '07  
GeneralRe: License questionmemberDan Letecky22:46 31 Jan '07  
GeneralEvent FreeTimeClickmemberRoseville14:32 5 Jan '07  
QuestionIs it possible to call Java Script FuntionmemberRoseville12:42 5 Jan '07  
GeneraloverlapswithmemberTommieKokkie11:44 18 Dec '06  
GeneralRe: overlapswithmemberDan Letecky12:56 18 Dec '06  
QuestionloadEventsToDaymemberTommieKokkie2:34 8 Dec '06  
AnswerRe: loadEventsToDaymemberDan Letecky22:58 10 Dec '06  
QuestionRefreshing DayPilot ControlmemberEnriqueSu6:21 17 Oct '06  
QuestionData binding & integration with webcontrols.calendar [modified]memberEnriqueSu14:46 15 Sep '06  
AnswerRe: Data binding & integration with webcontrols.calendarmemberDan Letecky21:58 2 Oct '06  
GeneralHow about and "Enabled" style/property?memberSpotnick4:47 13 Sep '06  
GeneralDayPilot 2.0.1 releasedmemberDan Letecky4:00 23 Jun '06  
Questioneditingmembereighteenpinkpandas4:18 12 Jun '06  
Generalappearancememberr.waymen22:56 11 Jun '06  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 21 Mar 2006
Editor: Rinish Biju
Copyright 2005 by Dan Letecky
Everything else Copyright © CodeProject, 1999-2009
Web16 | Advertise on the Code Project