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 Sub
Timesheet 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 Sub
Timesheet 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 Sub
Filtering 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 Sub
Read 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 Sub
Timesheet 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
)