Rudi Grobler

In the cloud

TimeslotPanel

leave a comment »

A while ago I wrote a couple of CodeProject articles on how to recreate a outlook calendar using WPF… Occasionally I still get emails from people asking… how can I make it work in silverligh? how can I show multiple day? etc…

“Hindsight is 20/20”

So, in the next couple of blog articles I will try and redesign this control and dissect the parts that make it work! I have a couple of “Design Goal”:

  • Work in Silverlight and WPF
  • Support multiple views (Day,Week,Month,etc)
  • Extensible and skinnable

Lets start with the basics, at the heart of this control is a flexible layout panel called a TimeslotPanel!

What is layout?

The short answer is that layout is simply the act of arranging a set of rectangles on the screen. Ok, that is maybe too simple but very close! WPF/Silverlight elements have no left, top, right & bottom properties… elements can now only suggest where thy want to be placed but the actual act of placing them is the job of the panel in which thy are contained! WPF/Silverlight provides many pre-baked layout panel like Grid, Canvas, DockPanel, WrapPanel & StackPanel but more importantly, thy allow you to extend this by creating your own layout panels!!!

To create your own layout panel you do need to understand that WPF/Silverlight uses what is called a 2-pass layout.

First, the parent asks each child what’s your size and then it tells each child where thy should be (and how big)! Simple, isn’t it?

The only “other” concept we need to know is that elements can suggest where thy want to be by using attached properties!

<Canvas>
    <TextBlock Text="I want to be 10px left and 10px from the top?"
                Canvas.Left="10" Canvas.Top="10" />
</Canvas>

In this sample, the TextBlock suggests that it wants to be 10px from the top and 10px from the left! Since it is contained in a Canvas (Which supports absolute positioning), that is exactly where it would be placed! Our TimeslotPanel will be using a similar concept… Items can suggest a timeslot where it wants to be placed and if this falls within the TimeslotPanel’s time & date ranges, it will be positioned accordingly!

Let’s take a sneak peak

<rg:TimeslotPanel>
    <Rectangle rg:TimeslotPanel.StartTime="10:00 2010/08/18" rg:TimeslotPanel.EndTime="14:00 2010/08/18" />
</rg:TimeslotPanel>

This will draw a rectangle starting 10:00 2010/08/18 and ending 14:00 2010/08/18 (If it falls in the date & time ranges)

Date & Time ranges

The TimeRange specifies the start and end time of a day (By default it will start at 06:00 and end 18:00)

public class TimeRange
{
    public TimeSpan Start { get; set; }
    public TimeSpan End { get; set; }
}

And a DateRange (By default will run from the start of the week Sunday to Saturday)

public class DateRange
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
}

Here is a quick sample of this panel in action

<rg:TimeslotPanel>
    <Border rg:TimeslotPanel.StartTime="10:00 2010/08/18" rg:TimeslotPanel.EndTime="14:00 2010/08/18" Background="Blue" />
    <Border rg:TimeslotPanel.StartTime="10:00 2010/08/29" rg:TimeslotPanel.EndTime="14:00 2010/08/29" Background="Yellow" />
    <Border rg:TimeslotPanel.StartTime="10:00 2010/09/01" rg:TimeslotPanel.EndTime="14:00 2010/09/01" Background="Blue" />
    <Border rg:TimeslotPanel.StartTime="06:00 2010/08/21" rg:TimeslotPanel.EndTime="7:00 2010/08/21" Background="SpringGreen" />
    <Border rg:TimeslotPanel.StartTime="13:00 2010/08/21" rg:TimeslotPanel.EndTime="17:00 2010/08/21" Background="SpringGreen" />
    <Border rg:TimeslotPanel.StartTime="08:00 2010/08/22" rg:TimeslotPanel.EndTime="9:00 2010/08/22" Background="SpringGreen" />
    <Border rg:TimeslotPanel.StartTime="10:00 2010/08/23" rg:TimeslotPanel.EndTime="14:00 2010/08/23" Background="Blue" />
    <Border rg:TimeslotPanel.StartTime="7:00 2010/08/24" rg:TimeslotPanel.EndTime="10:00 2010/08/24" Background="Azure" />
    <Border rg:TimeslotPanel.StartTime="13:00 2010/08/24" rg:TimeslotPanel.EndTime="15:30 2010/08/24" Background="Yellow" />
    <Border rg:TimeslotPanel.StartTime="14:00 2010/08/25" rg:TimeslotPanel.EndTime="15:30 2010/08/25" Background="Azure" />
    <Border rg:TimeslotPanel.StartTime="9:00 2010/08/28" rg:TimeslotPanel.EndTime="17:00 2010/08/28" Background="DarkOliveGreen" />
    <Border rg:TimeslotPanel.StartTime="7:00 2010/08/25" rg:TimeslotPanel.EndTime="9:30 2010/08/25" Background="Lime" />
    <Border rg:TimeslotPanel.StartTime="12:00 2010/08/26" rg:TimeslotPanel.EndTime="17:00 2010/08/26" Background="Lime" />
    <Border rg:TimeslotPanel.StartTime="18:00 2010/08/27" rg:TimeslotPanel.EndTime="19:00 2010/08/27" Background="Orange" />
</rg:TimeslotPanel>

PS. Note that I did not set the DateRange & TimeRange explicitly (which means it will use the defaults)

Here is how it looks

 

And that is it… As always, here is the code

A couple of Silverlight Gotchas?

  • No UIPropertyMetadata or FrameworkPropertyMetadata

Only PropertyMetadata is available in Silverlight. I used the FrameworkPropertyMetadata to automatically invalidate measure and arrange when the date or time ranges changed. this has to be done manually in Silverlight

  • No OnRender in Silverlight Panel

TimeslotPanel’s guide lines are drawn using the OnRender override and their is NO OnRender in Silverlight (Not sure how it’s done in the Silverlight Grid… Will check)

  • No default DateTimeConverter (TypeConverter) in Silverlight

Silverlight do not know how to convert a string based time/date to a actual DateTime object… I had to create a very simple DateTimeConverter

Also Read

Written by rudigrobler

September 27, 2011 at 6:38 pm

Posted in Uncategorized

Leave a comment