These are 2 free controls, ScheduleCalendar and ScheduleGeneral, designed to show scheduled events in the form of a table. They are simple versions of the so-called Gantt chart. They don't have advanced features such as dependencies and milestones, but on the other hand, they use templated databinding, so it's up to you, the developer, what you want to show.
The controls can be used for a broad variety of applications: time tables, resource usage planners, calendars, event schedulers, activities, reservations, sequences, project management, etc... See the demos for some examples.
The ScheduleCalendar control for instance will turn this data:
StartTime | EndTime | EventDate | Task |
---|---|---|---|
9:00 | 11:00 | 3/8/2004 | History |
9:00 | 10:00 | 3/9/2004 | Math |
10:00 | 11:00 | 3/9/2004 | Biology |
11:00 | 12:00 | 3/9/2004 | History |
9:00 | 10:00 | 3/10/2004 | Geology |
10:00 | 12:00 | 3/10/2004 | Math |
9:00 | 10:00 | 3/11/2004 | Economy |
10:00 | 12:00 | 3/11/2004 | Literature |
9:00 | 12:00 | 3/12/2004 | Sports |
9:00 | 11:00 | 3/15/2004 | History |
9:00 | 10:00 | 3/16/2004 | Math |
10:00 | 11:00 | 3/16/2004 | Biology |
11:00 | 12:00 | 3/16/2004 | History |
9:00 | 10:00 | 3/17/2004 | Geology |
10:00 | 12:00 | 3/17/2004 | Math |
9:00 | 10:00 | 3/18/2004 | Economy |
10:00 | 12:00 | 3/18/2004 | Literature |
9:00 | 12:00 | 3/19/2004 | Sports |
into this presentation:
The other control is the ScheduleGeneral. Here you can provide your own titles (you may think of people, resources or location names). Here's an example with TV stations:
Automatically, overlapping events will cause extra rows or columns to be added to the table, so that they can be shown correctly.
Overlapping items:
The controls are written in VB.NET, but they can be used in any ASP.NET application. You may need to slightly adapt some of the sample code below to match the language used in your application.
The controls are free and open source under the LGPL license.
You can install the controls in the standard way:
You may want to add the controls to the toolbox of your editor (Visual Studio, Web Matrix or C# Builder). This will allow you to set their properties in the Property Pane. Follow the editor's procedure to add a control to the toolbox.
In order to support IntelliSense in HTML View in Visual Studio (and to avoid some compiler warnings):
C:\Program
Files\Microsoft Visual Studio .NET 2003\Common7\Packages\schemas\xml
<body>
tag of any new web form as follows:
<body
xmlns:cc1="urn:http://www.rekenwonder.com/schedule">
where cc1 is
the TagPrefix of the schedule control (the one assigned in the "Register"
directive). I added three sets of demo files:
Unzip the zipfile with the demos to a subfolder of the wwwroot folder. Then, either create a virtual directory for this folder in IIS, or copy the schedule.dll or schedule2.dll file to the bin folder in wwwroot.
For the demo files with inline code, that's all you have to do. Just call the first demo page through the address http://localhost/<foldername>/demo1.aspx in your browser.
For the Visual Studio project, open Visual Studio and create a new blank solution. Right click the new solution in the Solution Explorer, choose Add - New Project From Web..., enter the url http://localhost/<foldername> (<foldername> is the folder where you unzipped the demo files), and click OK. Select the project file when prompted. You should also create a virtual directory for the demo folder.
For the Visual Web Developer 2005 project, open Visual Web Developer and choose "Open existing Web site". Browse to the folder where the demo files are located.
There are 2 ways to add the controls to your page:
<%@ Register TagPrefix="rw" Namespace="rw" Assembly="Schedule" %>
Then,
add a tag like this where you want the schedule to be displayed: <rw:ScheduleGeneral id="Schedule1" runat="server" >
<ItemTemplate>
</ItemTemplate>
</rw:ScheduleGeneral>
Of course, for the calendar version, you use
ScheduleCalendar.Protected WithEvents Schedule1 As rw.ScheduleGeneral
In the
code-behind page, also add this import statement: Imports rw
Make sure you use the appropriate settings.
The DataSource
property should be either a DataSet
,
a DataTable
or a DataView
. You can't databind to a
DataReader
, since the control must be able to sort the data
internally.
For each item on the schedule, the data source should provide a single record
containing a start value, an end value, and custom data (typically a description
of the task or event). For the ScheduleCalendar control when
TimeFieldsContainDate=false
, you also need a date value. For the
ScheduleGeneral control you also need a title value (for display on column/row
headers).
You need to set 3 properties (similar to the 2 properties
DataTextField
and DataValueField
that you have to set
for a bound ListBox or CheckBoxList):
ScheduleCalendar:
StartTimeField
: the database field (column) containing the
start of the event
EndTimeField
: the database field containing the end of the
event
DateField
: the database field providing the dates. This field
should be of type "Date" (exception: when
TimeFieldsContainDate
=true
this field is ignored,
see below). In a vertical layout, this field will be used for column titles.
In a horizontal layout, it will be used for row titles. ScheduleGeneral:
DataRangeStartField
: the database field (column) containing
the start of the event
DataRangeEndField
: the database field containing the end of
the event
TitleField
: the database field providing the titles. You can
think of some useful fields for titles: people names, locations, classrooms,
resources, etc...) In a vertical layout, this field will be used for column
titles. In a horizontal layout, it will be used for row titles. 1) and 2) can be thought of as time fields, but in general, any type of
sortable field (such as an integer) will do. Only when
TimeFieldsContainDate=true
for the ScheduleCalendar control, they
should contain date and time information, and when
FullTimeScale=True
, they should contain at least time information.
Note that there is no property to indicate which field contains the "Task" or "Event" information. Actually, this information can be anything: a field, a combination of multiple fields, etc... This is possible since the "Task" data is provided through a databinding expression in the Item template. Its simplest form would be something like this:
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem,"taskfieldname") %>
</ItemTemplate>
Optionally, you can set the ItemStyleField
. When its value is
not blank, the database field with this name will be used as a css style class
for the item. This lets you set the style for each item separately from the
data source.
Then, there's the FullTimeScale
property. When false (the
default value), only range values occurring in the data source are shown. When
true, a continuous time scale is displayed (like the Outlook calendar). For the
ScheduleGeneral control, this requires the DataRangeStartField
and
DataRangeEndField
fields in the data source to be of type
Date/Time.
The image below shows the the same item (Lunch from 12:30 to 13:30) in both cases:
|
|
When FullTimeScale
is true, there are 3 additional properties
that you can set:
TimeScaleInterval
: an integer value giving the number of
minutes for the interval (default=60)
StartOfTimeScale
: a timespan value setting the start time of
the time scale (default=8:00)
EndOfTimeScale
: a timespan value setting the end time of the
time scale (default=17:00). The highest value allowed here is 24:00
(midnight), which should be entered as "1.00:00" (one day, zero hours and
minutes). Two other important properties are IncludeEndValue
and ShowValueMarks
. When IncludeEndValue
is True
, the row with the end value will be included in the event.
Sometimes, this will result in a more logical presentation. However, when the items are adjacent (for
instance: one event ends at 10:00 AM, and another starts at the same time), it's
better to set IncludeEndValue
to False
. Otherwise, the items will be shown as overlapping. In this case, you can also set ShowValueMarks
to True
, which will add marks indicating the values, and the values will be shown in the middle of the item.
The default value is False
for both.
The image below shows the the same item (Lunch from 12:30 to 13:30) in all cases:
IncludeEndvalue = False and ShowValueMarks = False
12:30 |
Lunch from 12:30 to 13:30 |
13:00 | |
13:30 | |
14:00 |
IncludeEndValue = True (ShowValueMarks is ignored)
12:30 |
Lunch from 12:30 to 13:30 |
13:00 | |
13:30 | |
14:00 |
IncludeEndValue = False and ShowValueMarks = True
12:30 | ||
Lunch from 12:30 to 13:30 |
||
13:00 | ||
13:30 | ||
14:00 | ||
For the ScheduleCalendar control, you should set these additional properties:
NumberOfDays
: the number of days to show at a time.
The default value is 7, making it a weekly calendar.
NumberOfRepetitions
: the number of times to repeat the
number of days (the default setting is 1 repetition).
This will only work in vertical layout, meaning that the NumberOfDays
is shown once on top, and repeated according to the setting of
NumberOfRepetitions. StartDay
: the day of the week to start the calendar.
This property is only used when the NumberOfDays property is set to 7.
The default value is Monday.
StartDate
: date to start displaying events. If this date
is not on the same day of the week as the StartDay property, the control
will start displaying on the same day prior to the chosen date.
The default value is today's date. See the demos to
learn how to set today's date programmatically.
TimeFieldsContainDate
: when false (the default), the
DateField
property is used to extract dates for each item. This
means that items must start and end on the same day. If some of your items
span midnight, you should set TimeFieldsContainDate
to true, and
you should provide a full date and time in both the
StartTimeField
and EndTimeField
fields. In this
case, the DateField
property is ignored.
The ScheduleGeneral control has two additional properties:
AutoSortTitles
: When true, the titles are sorted automatically,
even when they are not sorted in the data source. When false, you may
provide your own sorting order for the titles, but make sure that the items
with the same titles are grouped together, and that for each title, the
items are sorted on DataRangeStartField first and on DataRangeEndField next.
(for example: if you want to sort on a field called "SortOrder",
the DataRangeStartField is "StartTime",
and the DataRangeEndField is "EndTime", use the sorting expression
"ORDER BY SortOrder ASC, StartTime ASC, EndTime ASC")
The default value for AutoSortTitles
is true.
SeparateDateHeader
: When true, an extra range of cells will
be added to group all events of the same date. This requires
DataRangeStartField
and DataRangeEndField
to be of
type DateTime
. The default is False.
|
|
For both the ScheduleCalendar and ScheduleGeneral controls, you can easily
switch between a vertical or a horizontal layout with the
Layout
property, even at run time.
The next step is to add the content of the templates.
You can right-click on the control to edit the templates, or you can create the templates in HTML view. Also look at the templates in the demo pages for samples.
First of all, you should provide the
ItemTemplate
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem,"taskfieldname") %>
</ItemTemplate>
With ASP.NET 2.0, you can use:
<ItemTemplate>
<%# Eval("taskfieldname") %>
</ItemTemplate>
If you want, you can combine information from several
fields in the database. You can also add controls, images, just like you can in
a Repeater or DataList control.
The other templates are for the headers. Especially in the case of a time and date fields, you may want to format the content for proper display.
For the ScheduleGeneral control:
TitleTemplate
You just show the data:
<TitleTemplate>
<%# Container.DataItem %>
</TitleTemplate>
RangeHeaderTemplate
Typically, you could display the range header item as a short time:
<RangeHeaderTemplate>
<%# Convert.ToDateTime(Container.DataItem).ToShortTimeString() %>
</RangeHeaderTemplate>
DateHeaderTemplate
(only used when
SeparateDateHeader
is set to true
) Typically, you could display the date header item as a short date:
<DateHeaderTemplate>
<%# Convert.ToDateTime(Container.DataItem).ToShortDateString() %>
</DateHeaderTemplate>
For the ScheduleCalendar control:
DateTemplate
You could typically display the date header as a short date:
<TitleTemplate>
<%# Convert.ToDateTime(Container.DataItem).ToShortDateString() %>
</TitleTemplate>
TimeTemplate
Typically, you could display the time header item as a short time:
<RangeHeaderTemplate>
<%# Convert.ToDateTime(Container.DataItem).ToShortTimeString() %>
</RangeHeaderTemplate>
In your code, don't forget to call the DataBind()
method.
Without this call, nothing will be shown.
Finally, there's the EmptyDataTemplate
. Optionally, you can
use this template to provide a message to be shown when no data is found in
the data source. This template is not used by the ScheduleCalendar control
when FullTimeScale=True.
You can now bind to a DataSourceControl, just like you can with a GridView control. Use the smart tag menu and the "Select Data Source" wizard.
The Schedule control can also be used in Master/Detail scenarios. Typically, you can link it to a FormView or a DetailsView control, which allows for easy editing of data items. Make sure to include a primary key field in the data source for the Schedule control, and set the DataKeyNames property to the name of that primary key field.
After adding the FormView or the DetailsView control, use the "Select Data Source" wizard. Use the WHERE button to link the control to the Schedule control.
If you have projects working with a version prior to 1.5, you need to upgrade them.
The Schedule class has been removed from the assembly, from now on you'll have to use either
ScheduleCalendar or ScheduleGeneral.
If your project contains a Schedule control with DisplayMode=Calendar:
If your project contains a Schedule control with DisplayMode=General:
Download the demo pages for samples showing you how the Schedule control could be used. In each sample, you can set the properties with the help of a form and you can add items. These samples use an Access database as the data source.
I decided to use a table for displaying all the items, instead of graphics. Graphics can put a heavy load on the server, and most importantly: a table can have child controls such as checkboxes and hyperlinks. By using templates, a developer has full control about the content of the items.
I used Microsoft's sample code for the TemplatedList control as a starting point.
I created a BaseSchedule control, which contains the code that is common for ScheduleGeneral and ScheduleCalendar.
First, all the information is extracted from the data source in order to create lists for the row and column headers. Any double values are removed, and the remainder is sorted in ascending order.
Next, an empty Table web control is built, with the correct number of rows and columns.
Then, the header items are added (row headers and column headers).
Finally, the scheduled items are added to the body of the table. The most difficult part is to calculate the position and span of each item, to merge the corresponding cells, and to check whether items don't overlap.
For the control to work correctly on postback, the control tree needs to be
rebuilt in exactly the same way (without setting any properties). To make this
possible, some information has to be stored in the control's
ViewState
:
In the CreateChildControls
method, this information is used to
build the control tree.
On postback, viewstate will be applied automatically to each child control, and their state will be restored magically.
For designer support, the controls are based on Andy Smith's SimpleTemplatedControlDesigner class.
For the ASP.NET 2.0 version, I derived from the new CompositeDataBoundControl class. I added the SelectedValue property, in order to enable master/detail scenarios with FormView and DetailsView controls.
The designers are derived from the new DataBoundControlDesigner class, which eliminates the need for the SimpleTemplatedControlDesigner code.
I had a lot of trouble figuring out how to do it in ASP.NET 2.0, since a lot of documentation was still missing mid 2005.
Here are some ideas for improvement:
DeleteCommand
event
TodayStyle
property (similar to the one in the Calendar
control)
If anyone decides to extend this control, or has any comments, bug reports or questions, then it would be great to hear from you.
All releases are fully backwards compatible, except when upgrading from a version prior to 1.5 to version 1.6 or later. For this special case, see the upgrading instructions above. In all other cases, your existing projects will not stop working.
SelectedValue
property.
SelectedIndexChanged
event.
NumberOfDays
for the ScheduleCalendar
control to allow for a number of days other than 7. The default value
is still 7.
NumberOfRepetitions
property.
Setting the Weeks property will still work, but it will not show up in
the property panel anymore.
StartDay
for the ScheduleCalendar
control to allow for a starting day other than Monday. This property is
ignored when the NumberOfDays is not 7. The default value is still Monday.
ShowValueMarks
allows for a better display of
adjacent items. See the demos and the explanation above.
DataRangeStartField
value of NULL for every title that you want to show up
(this solution courtesy of K. B. McHugh).
EmptyDataTemplate
property. Use this template to
provide content when no rows are found in the data source (typically, this
would just be a message saying something like "No data found".
ItemStyleField
, which is an optional
database field providing the item styles (in the form of a css class name).
If not provided, then the ItemStyle property and the AlternatingItemStyle
property will be used for all items.
This addition is courtesy of David Sanders.
AutoSortTitles
for the ScheduleGeneral
control. When true (the default value), the titles are sorted alphabetically
by the control according to the values in the RangeValueField (this was also
the method used in previous versions). When false, the titles are
not sorted by the control, and the order will be the one of the
items in the datasource. When using this option, make sure that the items
with the same titles are grouped together in the datasource before databinding.
If the titles are not grouped, unexpected results may occur.