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

Creating an Outlook Calendar Using WPF (Part 2)

Rate me:
Please Sign up or sign in to vote.
4.55/5 (21 votes)
11 Nov 2008CPOL2 min read 118.8K   7.2K   76   16
Part 2 in a series on how to create a replica of the Outlook Calendar (and Appointments) using WPF.

A life spent making mistakes is not only more honorable, but more useful than a life spent doing nothing.

- George Bernard Shaw

Introduction

After part 1, I decided to really concentrate on how to make the Calendar control better and more “professional”. Let's assume for a minute that I wanted to sell this control. If I buy a control, I expect decent design time support, and I want the control to be stylable. My first attempt fell short!!! Let's try and make it better…

Item Generation

In the previous version of the Calendar, all the CalendarLedgerItem and CalendarTimeslotItem were created manually! This is a big no, no…

The CalendarLedger is responsible for creating all the CalendarLedgerItems. Calling PopulateLedger() will dynamically create all the ledger items!

C#
private void PopulateLedger()
{
    if (_ledgerItems != null)
    {
        for (int i = 0; i < 24; i++)
        {
            CalendarLedgerItem item = new CalendarLedgerItem();
            item.TimeslotA = i.ToString();
            item.TimeslotB = "00";
            item.SetBinding(CalendarLedgerItem.StyleProperty, 
            GetOwnerBinding("CalendarLedgerItemStyle"));
            _ledgerItems.Children.Add(item);
        }
    }
}

The CalendarDay is also responsible for creating the CalendarTimeslotItems (by calling PopulateDay()).

Style, Style, Style

CalendarProperties.jpg

The Calendar currently exposes styles for the CalendarLedgerItem, CalendarTimeslotItem, and CalendarAppointmentItem.

All the styles are exposed as DependencyPropertys:

C#
public static readonly DependencyProperty CalendarTimeslotItemStyleProperty =
    DependencyProperty.Register("CalendarTimeslotItemStyle", 
                typeof(Style), typeof(Calendar));

public Style CalendarTimeslotItemStyle
{
    get { return (Style)GetValue(CalendarTimeslotItemStyleProperty); }
    set { SetValue(CalendarTimeslotItemStyleProperty, value); }
}

All that is now left to do is bind the StyleProperty of the CalendarLedgerItem, CalendarTimeslotItem, and CalendarAppointmentItem to these DependencyPropertys!

C#
timeslot.SetBinding(CalendarTimeslotItem.StyleProperty, 
        GetOwnerBinding("CalendarTimeslotItemStyle"));

Namespaces

By adding the following attribute...

C#
[assembly: XmlnsDefinition(http://schemas.rudigrobler.com/wpf/2008, 
    "RudiGrobler.Controls")]

... it is now very easy to reference my controls without needing to remember all the namespaces:

XML
xmlns:rg="http://schemas.rudigrobler.com/wpf/2008" 

Design Time Support

Visual Studio and Expression Blend design time support is currently a hot topic!

<>CalendarInToolbox.jpg

The Calendar control is actually composed of some primitives like the CalendarLedger, CalendarDay, etc. I do not want these primitives to show up in my toolbox! I only want my Calendar control to be “selectable”.

To remove controls from the toolbox, add the following attribute:

C#
[ToolboxBrowsable(false)]

Also notice the “cool” custom icon I now have! This is achieved by adding an embedded resource with a specific name (Calendar.Icon.bmp). The icon can also be specified by using the ThumbnailAttribute!

CalendarIcon.jpg

In Expression Blend, the property grid gets divided into categories!

C#
[Category("Calendar")] 

CalendarProperties.jpg

Each category also gets subdivided into a “Normal” section and an expander that has some “Advanced” properties.

To place a property in the “Advanced” expander:

C#
[EditorBrowsable(EditorBrowsableState.Advanced)]

Or to place it in the “Normal” section:

C#
[EditorBrowsable(EditorBrowsableState.Always)]

Named Parts

A common practice in designing reusable controls is to use named parts! In my Calendar control, I needed access to the CalendarDay control. To get access to this control, I started by giving it a name:

XML
<calendarledger x:name="PART_Ledger" />

The next step is to override the Calendar's OnApplyTemplate:

C#
CalendarDay _day;
public override void OnApplyTemplate()
{
    base.OnApplyTemplate();

    _day = GetTemplateChild(ElementDay) as CalendarDay;
    if (_day != null)
    {
        _day.Owner = this;
    }
}

In OnApplyTemplate, I try and locate the named part (by using GetTemplateChild()).

Now, I have full access to the CalendarDay control!!! The only other “thing” to notice here is that I also set the Owner of my CalendarDay. This allows my Calendar day to set bindings on its Owner:

C#
public Calendar Owner { get; set; }

private BindingBase GetOwnerBinding(string propertyName)
{
    Binding result = new Binding(propertyName);
    result.Source = this.Owner;
    return result;
}

A best practice in using named parts is to always start the name with PART_, and also to add the following attribute to your control:

C#
[TemplatePart(Name = CalendarLedger.ElementLedgerItems, Type = typeof(StackPanel))]

This attribute makes it easy to determine what type a named part should be!

Summary

That is it for part 2!!!

- Rudi Grobler

History

  • 11th November, 2008: Initial post.

License

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


Written By
South Africa South Africa
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionCalendar Pin
Member 1477626119-Mar-20 5:29
Member 1477626119-Mar-20 5:29 
AnswerRe: Calendar Pin
jr from Yaoundé9-Apr-20 12:43
jr from Yaoundé9-Apr-20 12:43 
QuestionMicrosoft.windows.design dll (for Toolbox Browsableattribute) Not found in C# project? Pin
Jagadeeswaran Natarajan4-Nov-13 21:27
professionalJagadeeswaran Natarajan4-Nov-13 21:27 
QuestionVery nice work! Pin
Ehab K21-May-12 7:46
Ehab K21-May-12 7:46 
QuestionCustom datepicker missing reference Pin
PerMEriksson5-Feb-12 17:58
PerMEriksson5-Feb-12 17:58 
QuestionWhy is CalendarAppointmentItem.StartTimeProperty a bool? Pin
Dr.Drew26-Dec-11 16:49
Dr.Drew26-Dec-11 16:49 
QuestionToolboxBrowsable should be in another assembly Pin
jibedoubleve11-Oct-11 3:20
jibedoubleve11-Oct-11 3:20 
QuestionWhy is are most controls are made static Pin
tompastom10-Jul-11 0:56
tompastom10-Jul-11 0:56 
GeneralCompile errors abound! Please advise. Pin
Mike74915-May-11 16:47
Mike74915-May-11 16:47 
GeneralRe: Compile errors abound! Please advise. Pin
el0321617-May-11 23:27
el0321617-May-11 23:27 
In visual studio open the references tree at both projects and see if any reference is not found. In my case, at the beginning I got the same error but when doing this I found out that the WPFToolkit was missing. It had a yellow triangle on it. I deleted it and then added it again at both project and the errors disappear.
GeneralMy vote of 1 Pin
Member 72477765-Aug-10 8:35
Member 72477765-Aug-10 8:35 
GeneralProblem compiling Pin
u060509414-Mar-10 21:37
u060509414-Mar-10 21:37 
GeneralCan't get this to work... only header is visible, no ledger or time. Pin
Justin Time29-May-09 10:37
Justin Time29-May-09 10:37 
GeneralRe: Can't get this to work... only header is visible, no ledger or time. Pin
Mtihc19-Nov-13 2:51
Mtihc19-Nov-13 2:51 
NewsNice start, needs more work +simple fix Pin
captainplanet012321-Jan-09 1:38
captainplanet012321-Jan-09 1:38 
QuestionVisibility by week ? Pin
supertoto0324-Nov-08 2:37
supertoto0324-Nov-08 2:37 

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.