Sample Project
The sample project includes:
C# Source Code
VB.NET Source Code
Visual Studio Solution
Sample SQL Server Database
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.
ASP.NET Core Timesheet
There is a new version of this tutorial available: ASP.NET Core Timesheet (.NET, SQL Server, Entity Framework)
Features
Monthly time sheet
Filtering by employee
Drag and drop editing
Daily summary
Requirements
.NET Framework 4.0+
Visual Studio
SQL Server 2014+
Initial Setup
Create a new ASP.NET WebForms project and add DayPilot.dll from the trial package to the Bin directory.
Monthly Timesheet View

Add a new ASP.NET scheduler control to the WebForms page. The Scheduler is designed to display calendar for multiple resources side-by-side (one resource per row) but it also supports Days mode (24 hours per row). This mode allows you to create the timesheet.
Switch the Scheduler Days mode using ViewType="Days":
<DayPilot:DayPilotScheduler
ID="DayPilotScheduler1"
runat="server"
...
ViewType="Days"
>
</DayPilot:DayPilotScheduler>In the code behind, we will configure the Scheduler to display a time sheet for the current month (StartDate and Days properties).
C#
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// ...
DayPilotScheduler1.StartDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
DayPilotScheduler1.Days = DateTime.DaysInMonth(DateTime.Today.Year, DateTime.Today.Month);
DayPilotScheduler1.DataSource = new DataManager().GetRecords(employee);
DayPilotScheduler1.DataBind();
}
}VB.NET
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
If Not IsPostBack Then
' ...
DayPilotScheduler1.StartDate = New Date(Date.Today.Year, Date.Today.Month, 1)
DayPilotScheduler1.Days = Date.DaysInMonth(Date.Today.Year, Date.Today.Month)
DayPilotScheduler1.DataSource = (New DataManager()).GetRecords(employee)
DayPilotScheduler1.DataBind()
End If
End SubTimesheet Properties
Now we can set the timesheet properties:
One cell will represent 15 minutes (
CellDuration="15")The header cells will be grouped by hour (
CellGroupBy="Hour")The cell width will be 25 pixels (
CellWidth="25")
<DayPilot:DayPilotScheduler
ID="DayPilotScheduler1"
runat="server"
ViewType="Days"
...
CellDuration="15"
CellGroupBy="Hour"
CellWidth="25"
/>
Apply a CSS Theme

Apply the Green theme to the timesheet using the Theme property.
You can also design your own theme using the online WYSIWYG theme designer.
<DayPilot:DayPilotScheduler
ID="DayPilotScheduler1"
runat="server"
ViewType="Days"
CellDuration="15"
CellGroupBy="Hour"
CellWidth="25"
...
Theme="scheduler_green"
/>ASP.NET Timesheet Business Hours

The timesheet uses a different color for business and non-business hours.
By default, the business hours are set to start at 9 am and end at 5 pm. You can use your own hours (use BusinessBeginsHour and BusinessEndsHour properties).
<DayPilot:DayPilotScheduler
ID="DayPilotScheduler1"
runat="server"
BusinessBeginsHour="9"
BusinessEndsHour="18"
>
</DayPilot:DayPilotScheduler>
You can se set custom cell background color using BeforeCellRender event handler.
C#
protected void DayPilotScheduler1_BeforeCellRender(object sender, BeforeCellRenderEventArgs e)
{
if (!e.IsBusiness)
{
e.BackgroundColor = "#e3e3e3";
}
}VB.NET
Protected Sub DayPilotScheduler1_BeforeCellRender(ByVal sender As Object, ByVal e As BeforeCellRenderEventArgs)
If Not e.IsBusiness Then
e.BackgroundColor = "#e3e3e3"
End If
End SubTimesheet Daily Totals

Create additional row header columns that will display daily timesheet totals.
<HeaderColumns>
<DayPilot:RowHeaderColumn Title="Date" Width="100" />
<DayPilot:RowHeaderColumn Title="Day" Width="100" />
<DayPilot:RowHeaderColumn Title="Total" Width="100" />
</HeaderColumns>You can set column values for each day using BeforeResHeaderRender event handler.
C#
protected void DayPilotScheduler1_OnBeforeResHeaderRender(object sender, BeforeResHeaderRenderEventArgs e)
{
e.Columns[0].Html = e.Date.ToString("dddd");
TimeSpan total = new DataManager().GetTotalMinutesForDay(e.Date);
if (total > TimeSpan.Zero)
{
e.Columns[1].Html = total.ToString("hh\\:mm");
}
}VB.NET
Protected Sub DayPilotScheduler1_OnBeforeResHeaderRender(ByVal sender As Object, ByVal e As BeforeResHeaderRenderEventArgs)
e.Columns(0).Html = e.Date.ToString("dddd")
Dim eid As String = CStr(If(DayPilotScheduler1.ClientState("employee"), DropDownListEmployee.SelectedValue))
Dim employee As Integer = Convert.ToInt32(eid)
Dim total As TimeSpan = (New DataManager()).GetTotalMinutesForDay(e.Date, employee)
If total > TimeSpan.Zero Then
e.Columns(1).Html = total.ToString("hh\:mm")
End If
End SubFiltering Timesheet Data by Employee

Add a DropDownList with a list of employees.
<div class="space">
Employee:
<asp:DropDownList
runat="server"
ID="DropDownListEmployee"
ClientIDMode="Static"
DataTextField="EmployeeName"
DataValueField="EmployeeId" />
</div>Store the selected drop down list value in the clientState property using jQuery. The clientState property will be persisted until page reload. It will be accessible on the server side using ClientState property. We will use it to filter the data source to display the timesheet for a specific employee.
To request a refresh of the timesheet control, use the commandCallBack() JavaScript method.
<script type="text/javascript">
$(document).ready(function () {
dp.clientState.employee = $("#<%= DropDownListEmployee.ClientID %>").val();
$("#<%= DropDownListEmployee.ClientID %>").change(function () {
dp.clientState.employee = this.value;
dp.commandCallBack("refresh");
});
});
</script>
On the server side, handle the Command event and reload the timesheet records.
C#
protected void DayPilotCalendar1_Command(object sender, CommandEventArgs e)
{
switch (e.Command)
{
case "refresh":
UpdateScheduler();
DayPilotScheduler1.Update(CallBackUpdateType.Full);
break;
}
}
VB.NET
Protected Sub DayPilotCalendar1_Command(ByVal sender As Object, ByVal e As CommandEventArgs)
Select Case e.Command
Case "refresh"
UpdateScheduler()
DayPilotScheduler1.Update(CallBackUpdateType.Full)
End Select
End SubRead the selected filter value using ClientState property in the UpdateScheduler() method.
If the ClientState["employee"] value is not available read the current DropDownList selection.
C#
private void UpdateScheduler()
{
string eid = (string) (DayPilotScheduler1.ClientState["employee"] ?? DropDownListEmployee.SelectedValue);
int employee = Convert.ToInt32(eid);
DayPilotScheduler1.StartDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
DayPilotScheduler1.Days = DateTime.DaysInMonth(DateTime.Today.Year, DateTime.Today.Month);
DayPilotScheduler1.DataSource = new DataManager().GetRecords(employee);
DayPilotScheduler1.DataBind();
DayPilotScheduler1.Update();
}
VB.NET
Private Sub UpdateScheduler()
Dim eid As String = CStr(If(DayPilotScheduler1.ClientState("employee"), DropDownListEmployee.SelectedValue))
Dim employee As Integer = Convert.ToInt32(eid)
DayPilotScheduler1.StartDate = New Date(Date.Today.Year, Date.Today.Month, 1)
DayPilotScheduler1.Days = Date.DaysInMonth(Date.Today.Year, Date.Today.Month)
DayPilotScheduler1.DataSource = (New DataManager()).GetRecords(employee)
DayPilotScheduler1.DataBind()
DayPilotScheduler1.Update()
End SubTimesheet Database Schema (SQL Server)

Here is the Microsoft SQL Server database schema used by the sample project:
[Timesheet] Table
CREATE TABLE [Timesheet](
[TimesheetId] [int] IDENTITY(1,1) NOT NULL,
[TimesheetIn] [datetime] NULL,
[TimesheetOut] [datetime] NULL,
[EmployeeId] [int] NOT NULL
)
[Employee] Table
CREATE TABLE [Employee](
[EmployeeId] [int] IDENTITY(1,1) NOT NULL,
[EmployeeName] [nvarchar](100) NOT NULL
)
DayPilot
