Sample Project
The sample project includes:
C# Source Code
VB.NET Source Code
Visual Studio 2019 Solution
Requirements
.NET Framework 4.0 or higher
Visual Studio 2019
Microsoft SQL Server 2014+ (Express)
Features
This tutorial shows how to create a timetable in an ASP.NET web application. It supports custom time slots (blocks), drag and drop event moving and resizing, and custom event colors.
Weekly timetable view
Displays time slots (blocks) with custom size (the block number is mapped to the hour component of a
DateTime
value)Inline editing of the block properties using active areas
Custom event color in combination with CSS styling
Loads events and blocks from SQL Server database.
Full calendar CSS styling
Integrates DayPilot Navigator for switching the week
C# and VB.NET source code included.
Sample database included.
License
Licensed for testing and evaluation purposes. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for ASP.NET WebForms.
Introduction
This tutorial doesn't cover the DayPilot ASP.NET Calendar basics. For more information about configuring the week view, loading events from a database or enabling the AJAX drag and drop operations (moving, resizing) please see the following tutorial:
1. Mapping Timetable Slots to Hours
Internally, the ASP.NET calendar control works with time slots of equal size. The maximum supported slot size is 60 minutes (CellDuration
property).
In order to show a timetable with custom blocks, it is necessary to map the block to the hour part of the DateTime
. This allows a maximum of 24 slots per day. It would be possible to map it to the minute part as well if needed (modify TimetableManager.cs/TimetableManager.vb class).
Day (June 1, 2021)
Block 1 => mapped as 2021-06-21T01:00:00
Block 2 => mapped as 2021-06-21T02:00:00
etc.
Day 2 (June 22, 2021)
Block 1 => mapped as 2021-06-22T01:00:00
Block 2 => mapped as 2021-06-22T02:00:00
etc.
We will limit the display to 7 time slots (using DayBeginsHour
, DayEndsHour
, HeightSpec
properties), each taking one hour (CellDuration
property). We will increase the default time cell size to 70 pixels (CellHeight
property):
<DayPilot:DayPilotCalendar
ID="DayPilotCalendar1"
runat="server"
...
CellDuration="60"
CellHeight="70"
DayBeginsHour="1"
DayEndsHour="8"
HeightSpec="Full"
/>
Now we will use BeforeTimeHeaderRender
to customize the time headers (vertical axis). We will replace the default text with the block name (start and end) as defined in the database. The real block start and end times are defined in the [Block]
database table:
The block start and end times (BlockStart
, BlockEnd
) are stored as DateTime
fields but only the time part is significant.
Our BeforeTimeHeaderRender
handler looks like this:
C#
protected void DayPilotCalendar1_OnBeforeTimeHeaderRender(BeforeTimeHeaderRenderEventArgs ea)
{
int id = ea.Start.Hours;
DataRow r = FindBlock(id);
ea.InnerHTML = String.Format("Block {0}<br/>{1}<br/>{2}", id, TimeFormatter.GetHourMinutes((DateTime)r["BlockStart"], DayPilotCalendar1.TimeFormat), TimeFormatter.GetHourMinutes((DateTime)r["BlockEnd"], DayPilotCalendar1.TimeFormat));
}
VB.NET
Protected Sub DayPilotCalendar1_OnBeforeTimeHeaderRender(ByVal ea As BeforeTimeHeaderRenderEventArgs)
Dim id As Integer = ea.Start.Hours
Dim r As DataRow = FindBlock(id)
ea.InnerHTML = String.Format("Block {0}<br/>{1}<br/>{2}", id, TimeFormatter.GetHourMinutes(CDate(r("BlockStart")), DayPilotCalendar1.TimeFormat), TimeFormatter.GetHourMinutes(CDate(r("BlockEnd")), DayPilotCalendar1.TimeFormat))
End Sub
It will replace the default header text (e.g. "1 AM") with the block details:
2. Timetable Block Editing
We will make the block properties (start and end time) editable by adding an active area to each time header cell:
The active area is added in BeforeTimeHeaderRender
event handler:
C#
protected void DayPilotCalendar1_OnBeforeTimeHeaderRender(BeforeTimeHeaderRenderEventArgs ea)
{
// ...
ea.Areas.Add(new Area().Width(15).Top(0).Bottom(0).Right(0).CssClass("resource_action_menu").Html("<div><div></div></div>").JavaScript("editBlock(e);"));
}
VB.NET
Protected Sub DayPilotCalendar1_OnBeforeTimeHeaderRender(ByVal ea As BeforeTimeHeaderRenderEventArgs)
Rem ...
ea.Areas.Add((New Area()).Width(15).Top(0).Bottom(0).Right(0).CssClass("resource_action_menu").Html("<div><div></div></div>").JavaScript("editBlock(e);"))
End Sub
It specifies the area dimensions, CSS class and associated action. This active area will execute editBlock()
JavaScript method when clicked. The editBlock()
methods opens a dialog box with block details:
The modal dialog is created using DayPilot.Modal.form() method from DayPilot Modal open-source library. This method lets you create a modal dialog with a dynamically-built form. You can design your own modal dialog using DayPilot Modal Builder application.
3. Custom Timetable Event Colors
The new event dialog allows users to add events to the timetable and specify event properties, including description and color.
Blocks are loaded from the database:
New.aspx.cs
C#
private void FillDropDownListStart()
{
DataTable blocks = new DataManager().GetBlocks();
foreach(DataRow r in blocks.Rows)
{
int id = Convert.ToInt32(r["BlockId"]);
DateTime start = (DateTime) r["BlockStart"];
DateTime end = (DateTime)r["BlockEnd"];
string name = String.Format("Block {0} ({1} - {2})", id, TimeFormatter.GetHourMinutes(start, TimeFormat.Auto), TimeFormatter.GetHourMinutes(end, TimeFormat.Auto));
ListItem item = new ListItem(name, id.ToString());
DropDownListStart.Items.Add(item);
}
}
VB.NET
Private Sub FillDropDownListStart()
Dim blocks As DataTable = (New DataManager()).GetBlocks()
For Each r As DataRow In blocks.Rows
Dim id As Integer = Convert.ToInt32(r("BlockId"))
Dim start As Date = CDate(r("BlockStart"))
Dim [end] As Date = CDate(r("BlockEnd"))
Dim name As String = String.Format("Block {0} ({1} - {2})", id, TimeFormatter.GetHourMinutes(start, TimeFormat.Auto), TimeFormatter.GetHourMinutes([end], TimeFormat.Auto))
Dim item As New ListItem(name, id.ToString())
DropDownListStart.Items.Add(item)
Next r
End Sub
DataManager.cs
C#
public DataTable GetBlocks()
{
var da = CreateDataAdapter("select * from [Block] order by [BlockId]");
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
VB.NET
Public Function GetBlocks() As DataTable
Dim da = CreateDataAdapter("select * from [Block] order by [BlockId]")
Dim dt As New DataTable()
da.Fill(dt)
Return dt
End Function
The event details are saved in the [Assignment]
table:
The event color field (AssignmentColor
) is used to store the event color. This field can't be mapped to the event color directly but we can do it in BeforeEventRender
event handler:
C#
protected void DayPilotCalendar1_BeforeEventRender(object sender, DayPilot.Web.Ui.Events.Calendar.BeforeEventRenderEventArgs e)
{
string color = (string) e.DataItem["AssignmentColor"];
if (!String.IsNullOrEmpty(color))
{
e.BackgroundColor = color;
e.BorderColor = color;
e.FontColor = "#ffffff";
}
}
VB.NET
Protected Sub DayPilotCalendar1_BeforeEventRender(ByVal sender As Object, ByVal e As DayPilot.Web.Ui.Events.Calendar.BeforeEventRenderEventArgs)
Dim color As String = CStr(e.DataItem("AssignmentColor"))
If Not String.IsNullOrEmpty(color) Then
e.BackgroundColor = color
e.BorderColor = color
e.FontColor = "#ffffff"
End If
End Sub
Timetable SQL Server Database
The timetable tutorial project includes an SQL Server database. The database file (daypilot.mdf
) can be found in the App_Data
directory.
The timetable application connects to the SQL Server database using a LocalDB connector:
web.config
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="daypilot" connectionString="data source=(LocalDB)\MSSQLLocalDB;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\daypilot.mdf" providerName="System.Data.SqlClient"/>
</connectionStrings>
...
</configuration>
Database Schema (DDL)
CREATE TABLE [dbo].[Assignment] (
[AssignmentId] BIGINT IDENTITY (1, 1) NOT NULL,
[AssignmentNote] VARCHAR (2000) NULL,
[AssignmentStart] DATETIME NOT NULL,
[AssignmentEnd] DATETIME NOT NULL,
[AssignmentColor] VARCHAR (50) NULL,
CONSTRAINT [PK_Assignment] PRIMARY KEY CLUSTERED ([AssignmentId] ASC)
);
CREATE TABLE [dbo].[Block] (
[BlockId] INT NOT NULL,
[BlockStart] DATETIME NOT NULL,
[BlockEnd] DATETIME NOT NULL,
CONSTRAINT [PK_Block] PRIMARY KEY CLUSTERED ([BlockId] ASC)
);