Click here to Skip to main content
Click here to Skip to main content

Creating an Outlook Calendar using WPF (Part 1)

By , 21 Oct 2008
 

Introduction

Microsoft Office is undoubtedly one of the best selling products in the world today! Thy always try and innovate… In this CodeProject article, I will try and recreate the Microsoft Outlook Calendar control using WPF.

All elements/controls in WPF are look-less! This reduces the need to create custom controls. A button is an element that supports clicking on it and then raising a Click event, but there is no restriction on how this button should look!

So, with my WPF think cap on, I tried to find a control that I could restyle to fit my calendar control… After trying out a few ideas, I decided to rather create a custom control.

Here are the basic elements of my custom Calendar control:

CalendarLedgerItem and CalendarLedger

Ledger.jpg

The ledger indicates the timeslot time.

CalendarTimeslotItem

Timeslot.jpg

Each day is divided into 30 minute slots (represented by CalendarTimeslotItem). CalendarTimeslotItem provides a very simple hover style to hint to the user that by clicking on the timeslot, you can add an appointment. The CalendarTimeslotItem also exposes (and raises) AddAppointmentEvent, which gets bubbled to the calendar (by clicking on the timeslot). CalendarTimeslotItem derives from ButtonBase.

public static readonly RoutedEvent AddAppointmentEvent = 
    EventManager.RegisterRoutedEvent("AddAppointment", RoutingStrategy.Bubble, 
    typeof(RoutedEventHandler), typeof(CalendarTimeslotItem));

CalendarAppointmentItem

AppointmentItem.jpg

CalendarAppointmentItem is a very generic container to show an appointment (similar to ListboxItem). I cheat a little by assuming that what every “item” CalendarDay binds to will have a StartTime and EndTime property!

<Setter Property="StartTime" Value="{Binding StartTime}" />
<Setter Property="EndTime" Value="{Binding EndTime}" />

[Note] I know this sucks a little… I will address this in part 2!

CalendarDay

The CalendarDay is the heart of our Outlook calendar. The CalendarDay derives from ItemsControl.

protected override DependencyObject GetContainerForItemOverride()
{            
    return new CalendarAppointmentItem();
}

protected override bool IsItemItsOwnContainerOverride(object item)
{
    return (item is CalendarAppointmentItem);
}

Each “item” added to the CalendarDay will implicitly have CalendarAppointmentItem as its container. This will all “magically” work, provided that the objects bound to the ItemsControl have the StartTime and EndTime properties!

TimeslotPanel

The last part we have to cover before we look at the calendar control is the TimeslotPanel. This custom layout panel will position each “item” in the CalendarDay control based on its start and end times!

<ItemsPanelTemplate>
    <local:TimeslotPanel />
</ItemsPanelTemplate>

Calendar

The Calendar adds an owner to the CalendarTimeslotItem.AddAppointmentEvent.

public static readonly RoutedEvent AddAppointmentEvent = 
    CalendarTimeslotItem.AddAppointmentEvent.AddOwner(typeof(CalendarDay));

Currently, the Calendar control is the only control that explicitly “knows” what the date is! It has a CurrentDate property.

public static readonly DependencyProperty CurrentDateProperty =
    DependencyProperty.Register("CurrentDate", typeof(DateTime), typeof(Calendar),
        new FrameworkPropertyMetadata((DateTime)DateTime.Now,
            new PropertyChangedCallback(OnCurrentDateChanged)));

The Calendar control also exposes two commands that can be used to change the current date:

public static readonly RoutedCommand NextDay = 
       new RoutedCommand("NextDay", typeof(Calendar));
public static readonly RoutedCommand PreviousDay = 
       new RoutedCommand("PreviousDay", typeof(Calendar));

Commands.jpg

These commands are self explanatory!

I have also created a very basic model:

Model.jpg

This model is used as the data source!

public static readonly DependencyProperty AppointmentsProperty =
    DependencyProperty.Register("Appointments", 
       typeof(IEnumerable<Appointment>), typeof(Calendar),
    new FrameworkPropertyMetadata(null, 
        new PropertyChangedCallback(Calendar.OnAppointmentsChanged)));

The only tricky part now is how to get the data bound to my Appointments property into my ItemsControl?

Introducing filters… Rob Conery’s MVC Storefront uses a similar approach!

public static class Filters 
{ 
    public static IEnumerable<Appointment> ByDate(
           thisIEnumerable<Appointment> appointments, DateTime date) 
    { 
        var app = froma inappointments 
                  wherea.StartTime.Date == date.Date 
                  selecta; 
        return app; 
    } 
}

This extension method allows me to “filter” my appointments by date (ignoring the time). Here is how it is currently used:

private void FilterAppointments()
{
    DateTime byDate = CurrentDate;
    CalendarDay day = this.GetTemplateChild("day") as CalendarDay;
    day.ItemsSource = Appointments.ByDate(byDate);

    TextBlock dayHeader = this.GetTemplateChild("dayHeader") as TextBlock;
    dayHeader.Text = byDate.DayOfWeek.ToString();
}

This approach allows me to relatively easily extend the calendar control to support a day or week view (by just adding multiple CalendarDay controls).

OutlookCalendar.jpg

And, that is it for part 1... If you found this article interesting, please vote for it, and also visit my blog!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

rudigrobler
South Africa South Africa
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberMr.Golffy3 Jan '13 - 20:45 
Thank you!! This is what I am looking for.
GeneralMy vote of 5memberWikusOlivier23 Aug '12 - 5:56 
Nicely Explained
GeneralMy vote of 5membermonaShahid16 Oct '11 - 6:02 
it is a great piece of work and very helpful for me...thank to rudigrobler
QuestionAdded appointments do not appear immediatelymemberadimas8 Sep '11 - 3:53 
Hi,
 
Right after adding an appointment the day control seems empty. But when I go to next day and then back to current, the appointment appears in its place.
 
Is it binding error? Or do I have to call some "Refresh" method?
QuestionInstructions for changing timeslot to roomsmemberkoolkabin@live.com21 Jun '11 - 7:07 
hi,
I am trying to use your control in my hotel reservation project. I need to use rooms instead of time slot.
 
how can i start off?
Freelance,
Web and Desktop Application Developer
Outsourcing Nepal

QuestionRefresh Calendarmemberserkan312331 May '11 - 1:15 
Hi All,
 
How can I refresh calendar without pressing any button.
 
Thank You
GeneralAdd into CalendarAppointmentItem more object (for ex. a TextBlock), but more also....memberDario Concilio4 Feb '11 - 22:55 
I add little modify to show several information into AppointmentItem.
For example I added TextBlock into border but TextWrapping property hasn't effect.
What do you think about this?
 
<Style TargetType="{x:Type local:CalendarAppointmentItem}">
<Setter Property="StartTime" Value="{Binding StartTime}" />
<Setter Property="EndTime" Value="{Binding EndTime}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CalendarAppointmentItem}">
<Border CornerRadius="4,4,4,4" BorderThickness="1,1,1,1" BorderBrush="#5D8CC9"
Background="#F1F5E3" Margin="1,1,5,1" Padding="3,1.5,0,1.5" >
<Border.Effect>
<DropShadowEffect Opacity="0.5" />
</Border.Effect>
<TextBlock Text="{Binding Subject}" TextWrapping="Wrap"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

GeneralMy vote of 5memberDario Concilio4 Feb '11 - 22:52 
very good
GeneralNeed same in Silverlight 3...memberSumi .D8 Apr '10 - 1:59 
Hi ,

Thats a very good article . I am looking for same thing in Silverlight 3 .
 
How can I get this in Silverlight 3 ?
GeneralRe: Need same in Silverlight 3...memberheyyan14 Jun '10 - 23:55 
try this one
 
http://slcalendarcontrol.codeplex.com/[^]
GeneralHelpmembereman.tabbara9 Dec '09 - 19:58 
can this be used for windows forms C# project?i need to create a caleder with tim slots and a part for entering the subject can u help me plz?
Questionmulti account?memberresideozsoy5 Oct '09 - 0:56 
Hi
Could you please tell me how I can add multi account on the calender?
Because I need to show all members appointment on the calender.
Thanks
QuestionCan i change?memberyukonn20 Aug '09 - 6:15 
Hi Sir,
 
Can i change Title Date(Day) to Other? Other means Room No. or other.
 

Regards,
GeneralRoutedEvent questionmembermvtongeren30 Jun '09 - 21:41 
Hi Rudi,
 
Looking good, but I have a question about the use of AddOwner in the Calendar section:
(actually it's somebody else's question: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/d2b379e9-12ee-4f51-b16d-b2816cedc5b2/[^] Smile | :) )
 
public static readonly RoutedEvent AddAppointmentEvent =
CalendarTimeslotItem.AddAppointmentEvent.AddOwner(typeof(CalendarDay));
 
Why is it of type CalendarDay? I always thought the type should be the class that the event is defined in, Calendar in this case. Does it have a special purpose here?
 
Thanks,
Marcel
QuestionConveting the Outlook Control to SilverlightmemberAnil_gupta24 May '09 - 6:27 
It’s really fantastic stuff. I need almost exactly the same in Silverlight. I converted it in Silverlight but I am facing a small issue. I want to provide support for multiple appointment at the same time all of them come parallellly. I did change in TimesSlotPanel and it’s working perfectly. The only issue appointment rectangle doesn’t resize itself if the subject is bigger. If you can provide me your E-mail address, I can forward you the sample. I already have invested a lot of time so if you can help me out, it would be really great for me.
My EmailId is anil_gupta29@yahoo.com
 
Anil Kumar Gupta

GeneralCreating an OutLook Calendar using WPF (Part 1)memberMember 263050330 Dec '08 - 8:29 
Hello Rudi:
I recently came across your code submission (posted on the CodeProject) for "Creating an OutLook Calendar using WPF (Part 1)". (I'm not sure if there is a Part 2 to the article yet)
 
In any case I found this very interesting and have a question for you. Is it possible to present the Calendar view in a Month view? Or have you provided code, which will allow the calendar to be presented with
large-blocks displaying the individual days in the month?
 
I am writing an application in C#, which needs to include a Month view display, as in Outlook. My application's data is populated via user-input from another screen, where the user makes several selections of data from the
screen, including clicking on a Microsoft MonthCalendar control for the date. The recorded data along with the date is saved to a SQL server 2008 compact database.
 
I would like to provide my users a way to switch to another screen, where a Month view Calendar (similar to Outlook) would tell them at a glance what appointments have been made on a given date.
 
Also, would it be possible to manipulate the view to display Sunday as the beginning day of each week.
Thank you in advance for your consideration to this matter.
 
Richard Arnold
GeneralMy vote of 2memberCharles Perreault17 Dec '08 - 7:01 
The example and given code simply doesn't work at all, but the idea to use a custom panel for layout, instead of using a simple Grid, is interesting.
GeneralPragtigmembermwdiablo28 Oct '08 - 10:07 
Flippen nice Rudi!! Smile | :)
 

GeneralRe: Pragtigmemberrudigrobler31 Oct '08 - 0:48 
Dankie
GeneralAdding Appointmentsmemberdennis oneill22 Oct '08 - 21:20 
I noticed adding appointments to the current day does not update the current view. How should this work, is there a missing raise event or should the observable collection automatically handle this?
 
dennis

QuestionDate format US?memberPaulLinton22 Oct '08 - 17:12 
This looks fantastic. I am looking forward to subsequent parts.
 
I am a complete newbie on wpf stuff and I have a question. The AddAppointmentWindow wants me to enter dates in US format. How would I change the code so that it uses the local computer's date/time format?
Thanks
Paul
AnswerRe: Date format US?memberPaulLinton22 Oct '08 - 17:41 
Worked it out myself. Change App.xaml.cs to
using System.Windows;
using System.Windows.Markup;
using System.Globalization;
<br /><br />
namespace OutlookCalendar
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        static App()
        {
            FrameworkElement.LanguageProperty.OverrideMetadata(
                typeof(FrameworkElement),
                new FrameworkPropertyMetadata(
                    XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
        }
    }
}

AnswerRe: Date format US?memberrudigrobler22 Oct '08 - 20:04 
Hi PaulLinton,
 
Tnx, the AddAppointmentWindow is something I just quickly put in to test... it suck currently!
 
Tnx for the tip on the date/time format thou!
 
Rudi
GeneralFantasticmemberquicoli22 Oct '08 - 0:45 
I was looking for something like that !
GeneralRe: Fantasticmemberrudigrobler22 Oct '08 - 0:51 
Thank you!
GeneralDate comparisonsmembernormanr21 Oct '08 - 23:31 
Instead of the slow string comparison used in:
a.StartTime.ToShortDateString() == date.ToShortDateString()
you should use:
a.StartTime.Date == date.Date
GeneralRe: Date comparisonsmemberrudigrobler21 Oct '08 - 23:40 
Tnx,
 
I will update my code!
GeneralVery cool!memberstrictly8621 Oct '08 - 22:38 
Looking forward to part 2
GeneralRe: Very cool!memberrudigrobler21 Oct '08 - 22:41 
Thank you!
GeneralA good startmvpSacha Barber21 Oct '08 - 22:35 
Bring the rest on
 
Sacha Barber
  • Microsoft Visual C# MVP 2008
  • Codeproject MVP 2008
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralRe: A good startmemberrudigrobler21 Oct '08 - 22:40 
Tnx Sacha,
 
There is still loads to do...

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

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 22 Oct 2008
Article Copyright 2008 by rudigrobler
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid