Click here to Skip to main content
15,860,972 members
Articles / Desktop Programming / WPF

Quick and Simple WPF Month-view Calendar

Rate me:
Please Sign up or sign in to vote.
4.92/5 (30 votes)
11 Mar 2009CPOL4 min read 217.3K   15.6K   81   42
A very simple, XAML-based month-view calendar that supports showing appointments, and exposes events.

Image 1

Introduction

While working on a freelance project recently (last month), I needed a basic month-view calendar control to use in a few places in the app. I searched, and found Creating an Outlook Calendar using WPF (by rudigobbler), which was a great day-view. I also found Richard Gavel's excellent on-going (I hope) work on Creating the Outlook UI with WPF (it's a 7-part series, so far).

Both of these are more serious efforts to create real, reusable components for other developers - but neither had a month-view. I was also in a time-crunch, as usual, and didn't really want to pay $800+ for a suite of WPF tools from one of the vendors. Since I really needed just very basic functionality, I took an afternoon and wrote this one.

Background

This article assumes you have a basic understanding of .NET and WPF. The code is not complicated, nor is it long. I make use of lambda functions (System.Predicate) in order to find appointments for each day, but that's about as complicated as it gets. Note that this requires .NET Framework 3.x - I built it on 3.5 SP1.

Using the code

The sample app (see download at top) shows the basic use of the calendar. Note that in Window1.xaml, I only include a reference to the local assembly, like so:

XML
xmlns:cal="clr-namespace:QuickWPFMonthCalendar"

Window1.xaml only contains one line of markup between the Window open and closing tags:

XML
<cal:MonthView x:Name="AptCalendar" VerticalAlignment="Stretch" 
               VerticalContentAlignment="Stretch"/>

This is Window1.xaml in Visual Studio 2008's design mode. As you can see, using it is pretty simple:

Image 2

The MonthView control exposes several events, which are declared in MonthView.xaml.vb like this:

VB
Public Event DisplayMonthChanged(ByVal e As MonthChangedEventArgs)
Public Event DayBoxDoubleClicked(ByVal e As NewAppointmentEventArgs)
Public Event AppointmentDblClicked(ByVal Appointment_Id As Integer)

I used two custom EventArgs structures, MonthChangedEventArgs and NewAppointmentEventArgs. This was mainly because I'm using other information in the application I built; you could just pass a date, or an ID, or an actual appointment object.

To handle the events, just write an event handler as you would for any control. In the sample app's Window1.xaml.vb, I used the following:

VB
Private Sub DayBoxDoubleClicked_event(ByVal e As NewAppointmentEventArgs) _
        Handles AptCalendar.DayBoxDoubleClicked
    MessageBox.Show("You double-clicked on day " & _
       CDate(e.StartDate).ToShortDateString(), _
       "Calendar Event", MessageBoxButton.OK)
End Sub

Private Sub AppointmentDblClicked(ByVal Appointment_Id As Integer) _
            Handles AptCalendar.AppointmentDblClicked
    MessageBox.Show("You double-clicked on appointment with ID = " & _
                    Appointment_Id, "Calendar Event", MessageBoxButton.OK)
End Sub

Private Sub DisplayMonthChanged(ByVal e As MonthChangedEventArgs) _
            Handles AptCalendar.DisplayMonthChanged
    Call SetAppointments()
End Sub

In the actual application I created this for, the Appointment class was generated by Visual Studio's LINQ-to-SQL designer, and it has more fields and functionality. For this demo, I stripped out everything LINQ-specific. MonthView stores appointments as a List(Of Appointment), which you set using the property MonthAppointments (ideally, you only pass the appointments the calendar needs to show that month). In this demo, I have a loop in the Window's Loaded event that creates appointments on 50 random days during the current year, and I pass only a filtered list (using List(Of T).FindAll) to MonthAppointments.

Also, note that setting the MonthAppointments property will automatically redraw the calendar to show the currently selected month. There is one other public property, DisplayStartDate (of type Date), which is used to determine the month and year to show (the day and time are ignored). Setting DisplayStartDate does not (possibly confusingly) cause the calendar to re-render with that month; this is because in my app, I always set some appointments (even if I assign an empty List(Of Appointment) to MonthAppointments).

Finally, there is a label that shows the currently-displayed month and year, plus forward and back-buttons, which update DisplayStartDate, and then raise the DisplayMonthChanged event.

Points of interest

In order to tell where a user has double-clicked (since it could be on an appointment, or in the blank part of a daybox control), I repurposed a function that I'm using in another part of the app, which was originally in C# and comes from Bea Stollnitz's blog.

Also - I included a small check in the code in MonthView.xaml.vb that shows some random appointments in design mode - this was so I could see what the appointments looked like without having to build/run. That code block looks like this:

VB
'-- for design mode, add appointments to random days for show...
If System.ComponentModel.DesignerProperties.GetIsInDesignMode(Me) Then
    If Microsoft.VisualBasic.Rnd(1) < 0.25 Then
        Dim apt As New DayBoxAppointmentControl()
        apt.DisplayText.Text = "Apt on " & i & "th"
        dayBox.DayAppointmentsStack.Children.Add(apt)
    End If
ElseIf ....

Obviously, you can safely take that out.

Keep in mind that this month view was a quick & dirty solution to a problem, and it definitely has some flaws. One main flaw is that if you have too many appointments in one day, they don't fit, and don't give you any visual cue. Also, it's all done with XAML building blocks, although you could grab the intermediate-built *.xaml.g.vb files and create a new project with all code, or just build it to a DLL and then reference it. As of now, it doesn't support styles, or anything else fancy - I'm just learning WPF as I do this project.

Hopefully, this rather ugly effort will prompt an expert in WPF to create a more full-featured and style-able control that we can all then use!

History

  • Version 0.1 - Posted March 11, 2009 (created in Feb. 2009) by Kirk Davis.

License

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


Written By
Software Developer (Senior)
Thailand Thailand
Just a .NET developer, mostly VB.NET and some C#, building applications and services using ASP.NET, WPF, WCF and Silverlight, as well as occasional project-management gigs.

Also - living abroad (in Thailand), originally planned for a year, but now just over seven years! Doh!

Comments and Discussions

 
QuestionPlease Help Pin
Member 1601286313-Jun-23 19:28
Member 1601286313-Jun-23 19:28 
QuestionFunctionality in adding events Pin
Member 1533001625-Nov-21 9:05
Member 1533001625-Nov-21 9:05 
Questioni want same project in c# pls Pin
jojo dipa27-Feb-21 0:15
jojo dipa27-Feb-21 0:15 
QuestionClearing the appointments Pin
Member 1376095421-Dec-18 8:30
Member 1376095421-Dec-18 8:30 
QuestionI got this message what should I declare first? Pin
Israel Reuben23-May-17 8:46
Israel Reuben23-May-17 8:46 
QuestionUse this project in c# .NET. Pin
manojpabani22-Jan-16 1:22
manojpabani22-Jan-16 1:22 
QuestionGet appointments from database Pin
Member 1124121723-Oct-15 10:03
Member 1124121723-Oct-15 10:03 
QuestionThe type or NameSpace name Visual does not exist in the namespace"System.windows.media"(are you missing any assembly) Pin
nisar mohamed27-Aug-14 18:40
nisar mohamed27-Aug-14 18:40 
GeneralWow! So good! Pin
Kovorka21-Feb-13 4:33
Kovorka21-Feb-13 4:33 
QuestionC# version Pin
Paolo Dellepiane17-Feb-12 0:03
Paolo Dellepiane17-Feb-12 0:03 
AnswerRe: C# version Pin
kirkaiya17-Feb-12 0:31
kirkaiya17-Feb-12 0:31 
AnswerRe: C# version Pin
viskalai6-Nov-12 20:15
viskalai6-Nov-12 20:15 
AnswerRe: C# version Pin
Member 1449962323-Aug-20 13:05
Member 1449962323-Aug-20 13:05 
QuestionNice Article.. I have C# version. Pin
Hema Bairavan14-Dec-11 23:50
Hema Bairavan14-Dec-11 23:50 
AnswerRe: Nice Article.. I have C# version. Pin
lhx88061917-Dec-11 17:52
lhx88061917-Dec-11 17:52 
AnswerRe: Nice Article.. I have C# version. Pin
vzmon4-Jun-21 3:30
vzmon4-Jun-21 3:30 
AnswerRe: Nice Article.. I have C# version. Pin
Member 1033223522-Nov-21 22:16
Member 1033223522-Nov-21 22:16 
QuestionNice article Pin
Le Duc Anh21-Jun-11 18:42
professionalLe Duc Anh21-Jun-11 18:42 
GeneralHI can anybody provide same above sample in WPF(C#) Pin
hemant.tawri21-Feb-11 4:02
hemant.tawri21-Feb-11 4:02 
GeneralRe: HI can anybody provide same above sample in WPF(C#) Pin
kirkaiya21-Feb-11 4:58
kirkaiya21-Feb-11 4:58 
GeneralRe: HI can anybody provide same above sample in WPF(C#) Pin
Hema Bairavan14-Dec-11 19:57
Hema Bairavan14-Dec-11 19:57 
QuestionAdd click event handler to day date box? Pin
BMWBear6-Jan-11 4:33
BMWBear6-Jan-11 4:33 
AnswerRe: Add click event handler to day date box? Pin
kirkaiya8-Jan-11 19:57
kirkaiya8-Jan-11 19:57 
Generalnice job Pin
cappuccyno12-Aug-10 18:50
cappuccyno12-Aug-10 18:50 
GeneralPet peeve... Pin
chaiguy13376-Aug-10 10:14
chaiguy13376-Aug-10 10:14 

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.