Sample Project

The sample project includes:

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. Buy a license.

Features

  • Monthly time sheet
  • Filtering by employee
  • Drag and drop editing
  • Daily summary

Requirements

Visual Studio 2010 Version

  • .NET Framework 4.0
  • Visual Studio 2010+
  • SQL Server 2008+ (Express)

Visual Studio 2012 Version

  • .NET Framework 4.0
  • Visual Studio 2012+
  • SQL Server 2012+ (Express)

Visual Studio 2013 Version

  • .NET Framework 4.0
  • Visual Studio 2013
  • SQL Server 2014 (Express)

Online Demo

Initial Setup

Create a new ASP.NET WebForms project and add DayPilot.dll from the trial package to the Bin directory.

Monthly Timesheet View

timesheet-asp.net-days.png

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 set 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

Adjust 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

timesheet-asp.net-css-theme.png

Apply the Green theme to the timesheet using 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"
/>

Highlight Business Hours

timesheet-asp.net-business-hours.png

Specify business hours (BusinessBeginsHour, BusinessEndsHour properties).

<DayPilot:DayPilotScheduler
    ID="DayPilotScheduler1" 
    runat="server" 

    BusinessBeginsHour="9"
    BusinessEndsHour="18"
>
</DayPilot:DayPilotScheduler>

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

Daily Totals

timesheet-asp.net-daily-totals.png

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>

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

timesheet-asp.net-employee.png

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 .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.

Request a timesheet refresh using commandCallBack().

<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 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)

timesheet-asp.net-sql-schema.png

[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
)