Link to home
Start Free TrialLog in
Avatar of CLoucas
CLoucas

asked on

Timesheet application design

I have customized the time tracking application from Microsoft to suit my client's business workflow.  One of their requirements is however to provide a timesheet entry screen that closely resembles their timesheet (currently an Excel sheet).

I am a newbie in asp.net and i don't have much experience in designing web forms apart from simple ones; I wonder what is the best way to move (i.e. design a custom web control, get a ready one?) I have only until the end of the year to deliver the project!

Any help is greatly appreciated.
Avatar of Justin_W
Justin_W

If your clients want the app to mimic Excel as closely as possible, the best bet would probably be to use a 3rd-party Grid control, since the vendor will have done most of the tricky work for you. The choice of which one to use would be based on your budget, requirements, and personal preferences.

You can take a look at this grid comparison article as a start:
http://www.informit.com/articles/article.asp?p=170917&rl=1
Did you customize the ASP.NET TimeTracker starter kit?  If so, I also had to create a Timesheet entry screen and can show you how I did it.
Avatar of CLoucas

ASKER

kraffay

Thanks a lot.  Yes I have customized the TimeTracker starter kit.  I would appreciate if you could show me how you created the Timesheet Entry screen.
First make a UserControl for your time entry.  I am using the free eEWorld masked textbox to save me the hassle of validators.  I highly recommmend it. Here's the Markup:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="UC_TimeSheetAddRow.ascx.cs"
    Inherits="UC_TimeSheetAddRow" %>

<%@ Register Assembly="eWorld.UI, Version=2.0.3.2310, Culture=neutral, PublicKeyToken=24d65337282035f2"
    Namespace="eWorld.UI" TagPrefix="ew" %>

<table width="100%" cellpadding="1" cellspacing="0" border="0">
    <tr valign="top" style="background-color: #D9E2EC;">
        <td style="width: 15%;">
            <asp:DropDownList ID="ddlProject" runat="server" DataTextField="Name" DataValueField="Id"
                CausesValidation="False" CssClass="dropDownSmall" AutoPostBack="true" OnSelectedIndexChanged="ddlProject_SelectedIndexChanged" />
        </td>
        <td style="width: 20%;">
            <asp:DropDownList ID="ddlCategory" runat="server" DataTextField="Name" DataValueField="Id"
                CssClass="dropDownSmall" />
        </td>
        <td style="width: 20%; text-align: left;">
            <asp:TextBox CssClass="inputSmall" ID="txtDesc" runat="server" MaxLength="1000" TextMode="MultiLine"></asp:TextBox></td>
        <td style="width: 5%; text-align: right;">
            <ew:NumericBox DecimalPlaces="2" PositiveNumber="true" CssClass="inputSmall" ID="txtMon" runat="server" Width="30px"/>
        </td>
        <td style="width: 5%; text-align: right">
            <ew:NumericBox DecimalPlaces="2" PositiveNumber="true" CssClass="inputSmall" ID="txtTue" runat="server" Width="30px"/>
        </td>
        <td style="width: 5%; text-align: right">
            <ew:NumericBox DecimalPlaces="2" PositiveNumber="true" CssClass="inputSmall" ID="txtWed" runat="server" Width="30px"/>
        </td>
        <td style="width: 5%; text-align: right;">
            <ew:NumericBox DecimalPlaces="2" PositiveNumber="true" CssClass="inputSmall" ID="txtThu" runat="server" Width="30px"/>
        </td>
        <td style="width: 5%; text-align: right;">
            <ew:NumericBox DecimalPlaces="2" PositiveNumber="true" CssClass="inputSmall" ID="txtFri" runat="server" Width="30px"/>
         </td>
        <td style="width: 5%; text-align: right;">
            <ew:NumericBox DecimalPlaces="2" PositiveNumber="true" CssClass="inputSmall" ID="txtSat" runat="server" Width="30px"/>
        </td>
        <td style="width: 5%; text-align: right;">
            <ew:NumericBox DecimalPlaces="2" PositiveNumber="true" CssClass="inputSmall" ID="txtSun" runat="server" Width="30px"/>
        </td>
        <td style="width: 10%; text-align: center;">
            <asp:ImageButton ID="lnkSave" runat="server" ImageUrl="~/TimeTracker/images/icon-save.gif"
                OnClick="lnkSave_Click" />
            &nbsp;
            <asp:ImageButton ID="lnkCancel" runat="server" ImageUrl="~/TimeTracker/images/icon-cancel.gif"
                OnClick="lnkCancel_Click" />
        </td>
    </tr>
</table>
<table>
    <tr>
        <td>
            <asp:Label ID="lblError" runat="server" />
        </td>
    </tr>
</table>
<asp:ObjectDataSource ID="ProjectData" runat="server" TypeName="ASPNET.StarterKit.BusinessLogicLayer.Project">
</asp:ObjectDataSource>
<asp:ObjectDataSource ID="ProjectCategories" runat="server" TypeName="ASPNET.StarterKit.BusinessLogicLayer.Category"
    SelectMethod="GetCategoriesByProjectId">
    <SelectParameters>
        <asp:ControlParameter Name="projectId" ControlID="ddlProject" PropertyName="SelectedValue"
            DefaultValue="0" Type="Int32" />
    </SelectParameters>
</asp:ObjectDataSource>
Here's the code behind for the control:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using ASPNET.StarterKit.BusinessLogicLayer;
using System.Collections.Generic;


public partial class UC_TimeSheetAddRow : System.Web.UI.UserControl
{

    //-- set up the events to notify the parent page of the control events
    public delegate void MessageHandler(Object sender, EventArgs e);
    public event MessageHandler OnSave;
    public event MessageHandler OnProjectChange;
    public event MessageHandler OnCancel;

    protected void Page_Load(object sender, EventArgs e)
    {

        if (!IsPostBack)
        {

            //-- nothing for now

        }
    }

    /// <summary>
    /// load the categories for the select project
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void ddlProject_SelectedIndexChanged(object sender, EventArgs e)
    {

        EventArgs changeArgs = new EventArgs();
        if (OnProjectChange != null)
        {
            OnProjectChange(this, changeArgs);
        }

        this.LoadCategories();
    }

    /// <summary>
    /// add the client side validation code and clear out the hours entry fields
    /// </summary>
    private void SetAddMode()
    {

        this.txtMon.Attributes.Add("onKeyPress", "return numbersonly(this, event);");
        this.txtTue.Attributes.Add("onKeyPress", "return numbersonly(this, event);");
        this.txtWed.Attributes.Add("onKeyPress", "return numbersonly(this, event);");
        this.txtThu.Attributes.Add("onKeyPress", "return numbersonly(this, event);");
        this.txtFri.Attributes.Add("onKeyPress", "return numbersonly(this, event);");
        this.txtSat.Attributes.Add("onKeyPress", "return numbersonly(this, event);");
        this.txtSun.Attributes.Add("onKeyPress", "return numbersonly(this, event);");

        this.txtMon.Text = string.Empty;
        this.txtTue.Text = string.Empty;
        this.txtWed.Text = string.Empty;
        this.txtThu.Text = string.Empty;
        this.txtFri.Text = string.Empty;
        this.txtSat.Text = string.Empty;
        this.txtSun.Text = string.Empty;

        //this.lblNoData.Text = string.Empty;

    }

    /// <summary>
    /// Get projects this user is assigned to
    /// </summary>
    /// <returns></returns>
    public bool LoadProjects()
    {
        try
        {

            List<Project> projects = Project.GetProjectsByUserName(Page.User.Identity.Name);

            if (projects.Count > 0)
            {
                this.ddlProject.DataSource = projects;
                this.ddlProject.DataBind();

                LoadCategories();

                SetAddMode();

                return true;
            }
            else
            {

                this.lblError.Visible = true;
                this.lblError.Text = "You do not have any projects assigned to you.";
                return false;
            }

        }
        catch
        {
            return false;
        }
    }

    private bool LoadCategories()
    {
        try
        {
            this.ddlCategory.DataSource = Category.GetCategoriesByProjectId(int.Parse(this.ddlProject.SelectedValue));
            this.ddlCategory.DataBind();
            return true;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// Save the data, refresh the grid
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void lnkSave_Click(object sender, EventArgs e)
    {

        //-- this will notify the container page that it needs to call saveData
        EventArgs saveArgs = new EventArgs();
        if (OnSave != null)
        {
            OnSave(this, saveArgs);
        }

        this.ddlCategory.Items.Clear();
        this.ddlProject.Items.Clear();

        foreach (Control ctl in this.Controls)
        {
            if (ctl is TextBox)
            {
                TextBox TextBox = (TextBox)ctl;
                TextBox.Text = string.Empty;
            }
        }

    }

    /// <summary>
    /// hide the add row panel
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void lnkCancel_Click(object sender, EventArgs e)
    {

        Panel pnlAddRow = (Panel)this.Parent.FindControl("pnlAddRow");

        LinkButton lnkAdd = (LinkButton)this.Parent.FindControl("lnkAdd");

        pnlAddRow.Visible = false;
        lnkAdd.Visible = true;

        EventArgs cancelArgs = new EventArgs();
        if (OnCancel != null)
        {
            OnCancel(this, cancelArgs);
        }

        //Session["AddNewRowCount"] = null;
    }

    private WeeklyHours _HoursForThisRow;
    public WeeklyHours HoursForThisRow
    {
        get
        {
            return _HoursForThisRow;
        }
        set
        {
            _HoursForThisRow = value;
        }
    }

    public bool SaveData()
    {
        try
        {

            Label lblMon = (Label)this.Parent.FindControl("lblMon");
            Label lblTue = (Label)this.Parent.FindControl("lblTue");
            Label lblWed = (Label)this.Parent.FindControl("lblWed");
            Label lblThu = (Label)this.Parent.FindControl("lblThu");
            Label lblFri = (Label)this.Parent.FindControl("lblFri");
            Label lblSat = (Label)this.Parent.FindControl("lblSat");
            Label lblSun = (Label)this.Parent.FindControl("lblSun");

            HoursForThisRow = new WeeklyHours();
           
            decimal hours = 0;

            if (this.txtMon.Text.Trim().Length > 0)
            {
                hours = decimal.Parse(this.txtMon.Text);
                AddEntry(hours, DateTime.Parse(lblMon.Text + "/" + DateTime.Now.Year));
                _HoursForThisRow.hoursMon = hours;
            }

            if (this.txtTue.Text.Trim().Length > 0)
            {
                hours = decimal.Parse(this.txtTue.Text);
                AddEntry(hours, DateTime.Parse(lblTue.Text + "/" + DateTime.Now.Year));
                _HoursForThisRow.hoursTue = hours;
            }

            if (this.txtWed.Text.Trim().Length > 0)
            {
                hours = decimal.Parse(this.txtWed.Text);
                AddEntry(hours, DateTime.Parse(lblWed.Text + "/" + DateTime.Now.Year));
                HoursForThisRow.hoursWed = hours;
            }

            if (this.txtThu.Text.Trim().Length > 0)
            {
                hours = decimal.Parse(this.txtThu.Text);
                AddEntry(hours, DateTime.Parse(lblThu.Text + "/" + DateTime.Now.Year));
                _HoursForThisRow.hoursThu = hours;
            }

            if (this.txtFri.Text.Trim().Length > 0)
            {
                hours = decimal.Parse(this.txtFri.Text);
                AddEntry(hours, DateTime.Parse(lblFri.Text + "/" + DateTime.Now.Year));
                _HoursForThisRow.hoursFri = hours;
            }

            if (this.txtSat.Text.Trim().Length > 0)
            {
                hours = decimal.Parse(this.txtSat.Text);
                AddEntry(hours, DateTime.Parse(lblSat.Text + "/" + DateTime.Now.Year));
                _HoursForThisRow.hoursSat = hours;
            }

            if (this.txtSun.Text.Trim().Length > 0)
            {
                hours = decimal.Parse(this.txtSun.Text);
                AddEntry(hours, DateTime.Parse(lblSun.Text + "/" + DateTime.Now.Year));
                _HoursForThisRow.hoursSun = hours;
            }

            return true;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// Save the hours
    /// </summary>
    /// <param name="hours"></param>
    /// <param name="date"></param>
    /// <returns></returns>
    private bool AddEntry(Decimal hours, DateTime date)
    {
        TimeEntry timeEntry = new TimeEntry(Page.User.Identity.Name, Convert.ToInt32(ddlCategory.SelectedValue),
            hours, date, Page.User.Identity.Name);

        timeEntry.Description = this.txtDesc.Text;
        timeEntry.Save();

        return true;
    }



}


Now's here's the Markup for the page that will host the control.  I am using the free obout calendar, which I also recommend.  Each time a user clicks "Add", an instance of the UC_TimeSheetAddRow is add to the page:

<%@ Page Language="C#" MasterPageFile="~/TimeTracker/MasterPage.master"
CodeFile="TimeSheetEntry.aspx.cs" Inherits="TimeSheetEntry" Title="TimeSheet Entry" Culture="auto" UICulture="auto" %>
<%@ Register TagPrefix="obout" Namespace="OboutInc.Calendar2" Assembly="obout_Calendar2_NET" %>
<%@ Register Src="UC_TimeSheetAddRow.ascx" TagName="UC_TimeSheetAddRow" TagPrefix="uc1" %>
<%@ Reference Control="~/TimeTracker/UC_TimeSheetAddRow.ascx" %>

<asp:Content ID="Content1" ContentPlaceHolderID="maincontent" Runat="Server">
<div id="adminedit">
        <a name="content_start" id="content_start"></a>
        <div id="divError" style="width: 500px;">
            <asp:Label runat="server" ID="lblError" CssClass="error" ForeColor="Maroon" Width="500px" />
        </div>
        <asp:Panel ID="pnlTimesheet" runat ="server" >
        <fieldset>
            <!-- add H2 here and hide it with css since you can not put h2 inside a legend tag -->
            <h2 class="none">
                Timesheet</h2>
            <legend>Timesheet</legend>
            <table width="95%" cellpadding="2" cellspacing="2">
                <tr>
                    <td>
                    <fieldset>
                        <table width="100%" >
                            <tr>
                                <td>
                                    Select Week:&nbsp;
                                    <asp:TextBox Enabled="false" ID="txtDate" runat="server" />
                                    <obout:Calendar ID="calWeek" DatePickerImagePath="~\TimeTracker\images\icon2.gif" TextBoxId="txtDate"
                                        DatePickerMode="true"  StyleFolder="~\TimeTracker" runat="server" AutoPostBack="True">
                                    </obout:Calendar>
                                </td>
                                <td style="text-align:right;">
                               
                                     <asp:LinkButton                                        
                                        ID="lnkAdd"
                                        runat = "server"
                                        Text="Add"
                                        Visible="false" OnClick="lnkAdd_Click"/>
                                     
                                </td>
                            </tr>
                        </table>
                    </fieldset>
                    </td>                
                </tr>
               
                <asp:panel ID="pnlGrid" runat="server" Visible="false">
                <tr>
                    <td>
                        <table width="100%" cellpadding="0" cellspacing="0">
                            <tr>
                                <td colspan="11">
                                    <img alt="" src="../TimeTracker/images/spacer.gif" height="1px" width="900px" />
                                </td>
                            </tr>
                            <tr valign="bottom">
                                <td style="width: 15%;">
                                </td>
                                <td style="width: 20%;">
                                </td>
                                <td style="width: 19%; text-align: left;">
                                </td>
                                <td style="width: 5%; text-align: right;">
                                    <asp:Label ID="lblMon" runat="server" /></td>
                                <td style="width: 5%; text-align: right;">
                                    <asp:Label ID="lblTue" runat="server" />
                                </td>
                                <td style="width: 5%; text-align: right;">
                                    <asp:Label ID="lblWed" runat="server" />
                                </td>
                                <td style="width: 5%; text-align: right;">
                                    <asp:Label ID="lblThu" runat="server" />
                                </td>
                                <td style="width: 5%; text-align: right;">
                                    <asp:Label ID="lblFri" runat="server" />
                                </td>
                                <td style="width: 5%; text-align: right;">
                                    <asp:Label ID="lblSat" runat="server" />
                                </td>
                                <td style="width: 5%; text-align: right;">
                                    <asp:Label ID="lblSun" runat="server" />
                                </td>
                                <td style="text-align: center;">
                                    &nbsp; &nbsp;
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
                <tr>
                    <td valign="top">
                        <asp:GridView ID="grdTimesheet"
                            AutoGenerateColumns="False"
                            AllowSorting="False"
                            AllowPaging="False"
                            runat="server"
                            Width="100%"
                            CellPadding="2"
                            CellSpacing="1"
                            AlternatingRowStyle-BackColor="#D9E2EC"
                            PageSize="25"
                            BackColor="LightGrey"  
                            GridLines="None"  
                            ShowFooter="true"
                            OnRowDataBound = "grdTimesheet_OnRowDatabound"
                            style="border-right: black 1px solid; border-top: black 1px solid; border-left: black 1px solid; border-bottom: black 1px solid"
                            OnRowDeleting="grdTimesheet_OnRowDeleting"
                            FooterStyle-HorizontalAlign="right" FooterStyle-Font-Bold="true" >
                            <Columns>
                                <asp:BoundField DataField="ProjectName" HeaderText="Project">
                                    <ItemStyle Width="15%" />
                                </asp:BoundField>
                               
                                <asp:BoundField DataField="CategoryName" HeaderText="Category">
                                    <ItemStyle Width="20%" />
                                </asp:BoundField>
                               
                                <asp:BoundField DataField="TimeEntryDescription" HeaderText="Desc">
                                    <ItemStyle Width="19%" />
                                </asp:BoundField>
                               
                                <asp:BoundField DataField="MON"  
                                    HeaderText="MON">
                                    <ItemStyle HorizontalAlign="Right" Width="5%" />
                                    <HeaderStyle HorizontalAlign="Right"  />
                                </asp:BoundField>
                               
                                <asp:BoundField
                                    DataField="TUE"
                                    HeaderText="TUE">
                                    <ItemStyle HorizontalAlign="Right" Width="5%" />
                                    <HeaderStyle HorizontalAlign="Right" />
                                </asp:BoundField>
                               
                                <asp:BoundField
                                    DataField="WED"
                                    HeaderText="WED">
                                    <ItemStyle HorizontalAlign="Right" Width="5%" />
                                    <HeaderStyle HorizontalAlign="Right" />
                                </asp:BoundField>
                               
                                <asp:BoundField
                                    DataField="THU"
                                    HeaderText="THU">
                                    <ItemStyle HorizontalAlign="Right" Width="5%" />
                                    <HeaderStyle HorizontalAlign="Right" />
                                </asp:BoundField>
                               
                                <asp:BoundField
                                    DataField="FRI"
                                    HeaderText="FRI">
                                    <ItemStyle HorizontalAlign="Right" Width="5%" />
                                    <HeaderStyle HorizontalAlign="Right" />
                                </asp:BoundField>

                                <asp:BoundField
                                    DataField="SAT"
                                    HeaderText="SAT">
                                    <ItemStyle HorizontalAlign="Right" Width="5%" />
                                    <HeaderStyle HorizontalAlign="Right" />
                                </asp:BoundField>

                                <asp:BoundField
                                    DataField="SUN"
                                    HeaderText="SUN">
                                    <ItemStyle HorizontalAlign="Right" Width="5%" />
                                    <HeaderStyle HorizontalAlign="Right" />
                                </asp:BoundField>
                           
                                <asp:TemplateField ShowHeader="False">
                                    <HeaderStyle Width="10%"  />
                                    <ItemStyle HorizontalAlign="Center"/>
                                    <ItemTemplate>
                                        <asp:ImageButton ID="btnDelete" runat="server"
                                            CausesValidation="False" CommandName="Delete" ImageUrl="images/icon-delete.gif" />
                                    </ItemTemplate>
                                    <FooterStyle HorizontalAlign="Center"/>
                                </asp:TemplateField>
                           
                            </Columns>
                           
                           
                           
                            <RowStyle HorizontalAlign="Left" CssClass="row1" VerticalAlign="Top" />
                            <HeaderStyle CssClass="grid-header" HorizontalAlign="Left" BackColor="LightGrey" ForeColor="black"  />
                            <AlternatingRowStyle />
                            <EmptyDataRowStyle CssClass="grid-header"  Font-Bold="true"  />
                           
                            <EmptyDataTemplate>
                                <table cellpadding="0"  cellspacing="1" width="100%" style="background-color:LightGrey;"   >
                               
                                    <tr class="grid-header"  style="background-color:LightGrey; color:Black;"  >
                                        <td style="width: 15%;">
                                            Project</td>
                                        <td class="grid-header" style="width: 20%;">
                                            Category</td>
                                        <td style="width: 20%; text-align: left;">
                                            Desc
                                        </td>
                                        <td style="width: 5%; text-align: right;">
                                            MON
                                        </td>
                                        <td style="width: 5%; text-align: right">
                                            TUE
                                        </td>
                                        <td style="width: 5%; text-align: right">
                                            WED
                                        </td>
                                        <td style="width: 5%; text-align: right;">
                                            THU
                                        </td>
                                        <td style="width: 5%; text-align: right;">
                                            FRI
                                        </td>
                                        <td style="width: 5%; text-align: right;">
                                            SAT
                                        </td>
                                        <td style="width: 5%; text-align: right;">
                                            SUN
                                        </td>
                                        <td style="width: 10%; text-align: center;">
                                            &nbsp;
                                        </td>
                                    </tr>
                                </table>
                            </EmptyDataTemplate>
                           
                        </asp:GridView>
                    </td>
                </tr>
                    <tr>
                        <td style="text-align: right;">
                            <asp:LinkButton ID="lnkExportToWord" runat="server" Text="Export To Word" Visible="True" OnClick="lnkExport_Click" />
                        </td>
                    </tr>
                </asp:panel>                
                <asp:Panel ID="pnlAddRow" runat="server" Visible="false" >
                <tr>
                    <td style="background-color:#D9E2EC;" class="inputSmall">
                       
                        <asp:PlaceHolder EnableViewState="true" ID="phAddRow" runat="server" />
                   
                    </td>
                </tr>
                </asp:Panel>
                <tr>
                    <td>
                     <asp:Label runat="server" ID="lblNoData" CssClass="error" ForeColor="Maroon" Width="500px" />
                    </td>
                </tr>
            </table>
        </fieldset>
        </asp:Panel>
    </div>

</asp:Content>

And here's the code behind for the page:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Collections.ObjectModel;
using ASPNET.StarterKit.BusinessLogicLayer;
using System.Threading;
using System.Collections.Generic;


public partial class TimeSheetEntry : System.Web.UI.Page
{
    //public event EventHandler Init=null;
    private UC_TimeSheetAddRow TimeSheetAddRow;
    private WeeklyHours TotalHoursByDay = new WeeklyHours();

    #region "Page Events"
    /// <summary>
/// Loop through all the add row controls and save the data.  Then hide the add row panel and reload the grid.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
    public void UC_TimeSheetAddRow_Saved(object sender, EventArgs e)
    {

        this.ClientScript.RegisterClientScriptBlock(this.GetType(), "alert", "alert('Data Saved!')", true);
        this.pnlAddRow.Visible = false;

        _HoursForThisWeek = new WeeklyHours();

        int iCount = phAddRow.Controls.Count;
        for (int i = 0; i < iCount; i++)
        {
            TimeSheetAddRow = (UC_TimeSheetAddRow)phAddRow.Controls[i];
            TimeSheetAddRow.SaveData();

            //accumulate the hours as we save
            AccumulateHours(TimeSheetAddRow);
        }      
       
        LoadGrid();
        this.lnkAdd.Visible = true;
        Session["AddNewRowCount"] = null;
        this.RemoveAllAddRows();

    }

    public void UC_TimeSheetAddRow_OnProjectChange(object sender, EventArgs e)
    {
        //HACK - adjust the row count to keep this event from added an extra row
        phAddRow.Controls.RemoveAt(phAddRow.Controls.Count - 1);
    }

    public void UC_TimeSheetAddRow_Cancel(object sender, EventArgs e)
    {
        this.pnlAddRow.Visible = false;
        this.RemoveAllAddRows();
        this.grdTimesheet.Enabled = true;
        Session["AddNewRowCount"] = null;
        this.lnkExportToWord.Visible = true;
    }

    protected void Page_Init(object sender, EventArgs e)
    {

        if (this.IsPostBack)
        {
            //-- dynamically load the new row user controls here so that the view state is preserved

            if (Session["AddNewRowCount"] == null)
            {
                Session["AddNewRowCount"] = 1;
            }

            int iCount = int.Parse(Session["AddNewRowCount"].ToString());
            for (int i = 0; i < iCount; i++)
            {
                TimeSheetAddRow = (UC_TimeSheetAddRow)this.LoadControl("UC_TimeSheetAddRow.ascx");
                this.phAddRow.Controls.Add(TimeSheetAddRow);

                TimeSheetAddRow.OnSave += new UC_TimeSheetAddRow.MessageHandler(UC_TimeSheetAddRow_Saved);
                TimeSheetAddRow.OnProjectChange += new UC_TimeSheetAddRow.MessageHandler(UC_TimeSheetAddRow_OnProjectChange);
                TimeSheetAddRow.OnCancel += new UC_TimeSheetAddRow.MessageHandler(UC_TimeSheetAddRow_Cancel);

                TimeSheetAddRow.LoadProjects();
            }
        }
       
    }

    private void RemoveAllAddRows()
    {
        //-- remove all add rows
        int iCount = phAddRow.Controls.Count;
        for (int i = 0; i < iCount; i++)
        {
            phAddRow.Controls.RemoveAt(phAddRow.Controls.Count - 1);
        }

        Session["AddNewRowCount"] = null;
    }
    protected void Page_Load(object sender, EventArgs e)
    {

        if (!this.IsPostBack)
        {
            if (!this.UserHasProjects(Page.User.Identity.Name) && 
                (Page.User.IsInRole("ProjectAdminstrator"))
                && (!Page.User.IsInRole("ProjectManager")))
            {

                this.lblError.Visible = true;
                this.lblError.Text = "You do not have any projects assigned to you.";
                this.pnlTimesheet.Visible = false;

            }

            this.calWeek.SelectedDate = DateTime.Now;
            this.SelectedDate = DateTime.Now.ToString();
            this.txtDate.Text = this.calWeek.SelectedDate.ToString();


            this.lnkAdd.Visible = true;
            this.lblNoData.Text = string.Empty;
            this.pnlGrid.Visible = true;
            this.WeekNum = GetWeekNum(this.calWeek.SelectedDate);
            LoadGrid();

            RemoveAllAddRows();
        }
        else
        {
            //-- make sure we are not posting back from a grid delete event
            if (this.SelectedDate != null)
            {
                if (this.SelectedDate != this.calWeek.SelectedDate.ToString())
                {
                    this.WeekNum = GetWeekNum(this.calWeek.SelectedDate);
                    this.SelectedDate = this.calWeek.SelectedDate.ToString();
                    LoadGrid();
                    this.pnlAddRow.Visible = false;
                    RemoveAllAddRows();
                }
            }
            else
            {
                this.WeekNum = GetWeekNum(this.calWeek.SelectedDate);
                this.SelectedDate = this.calWeek.SelectedDate.ToString();
            }
        }
    }


    /// <summary>
    /// delete the record
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void grdTimesheet_OnRowDeleting(object sender, GridViewDeleteEventArgs e)
    {

        //-- extract the values out of the grid
        string TimeEntryDescription, CategoryName;

        TimeEntryDescription = grdTimesheet.Rows[e.RowIndex].Cells[(int)TimeSheetCells.TimeEntryDescription].Text;
        CategoryName = grdTimesheet.Rows[e.RowIndex].Cells[(int)TimeSheetCells.CategoryName].Text;

        TimeEntryDescription = TimeEntryDescription.Replace("&nbsp;", "");
        CategoryName = CategoryName.Replace("&nbsp;", "");

        Vw_aspnet_HoursPivot_BO bo = new Vw_aspnet_HoursPivot_BO();

        //-- delete the records from time entry that match this Cat/Desc/Week combo
        if (bo.DeleteTimeEntry(this.WeekNum, TimeEntryDescription, CategoryName))
        {
            //-- confirm and refresh

            this.ClientScript.RegisterClientScriptBlock(this.GetType(), "confirm", "alert('Record deleted!');", true);

            LoadGrid();
        }
    }

    protected void grdTimesheet_OnRowDatabound(object sender, GridViewRowEventArgs e)
    {

        int index = 0;

        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            index = e.Row.RowIndex;
            TotalHoursByDay.hoursMon += Decimal.Parse(e.Row.Cells[(int)TimeSheetCells.HoursMon].Text.ToString());
            TotalHoursByDay.hoursTue += Decimal.Parse(e.Row.Cells[(int)TimeSheetCells.HoursTue].Text.ToString());
            TotalHoursByDay.hoursWed += Decimal.Parse(e.Row.Cells[(int)TimeSheetCells.HoursWed].Text.ToString());
            TotalHoursByDay.hoursThu += Decimal.Parse(e.Row.Cells[(int)TimeSheetCells.HoursThu].Text.ToString());
            TotalHoursByDay.hoursFri += Decimal.Parse(e.Row.Cells[(int)TimeSheetCells.HoursFri].Text.ToString());
            TotalHoursByDay.hoursSat += Decimal.Parse(e.Row.Cells[(int)TimeSheetCells.HoursSat].Text.ToString());
            TotalHoursByDay.hoursSun += Decimal.Parse(e.Row.Cells[(int)TimeSheetCells.HoursSun].Text.ToString());

            ImageButton btnDelete = (ImageButton)e.Row.FindControl("btnDelete");
            btnDelete.Attributes.Add("onclick", "return confirm('Are you sure you want to delete this record?');");
        }
        else if (e.Row.RowType == DataControlRowType.Footer)
        {
            e.Row.Cells[(int)TimeSheetCells.HoursMon].Text = TotalHoursByDay.hoursMon.ToString();
            e.Row.Cells[(int)TimeSheetCells.HoursTue].Text = TotalHoursByDay.hoursTue.ToString();
            e.Row.Cells[(int)TimeSheetCells.HoursWed].Text = TotalHoursByDay.hoursWed.ToString();
            e.Row.Cells[(int)TimeSheetCells.HoursThu].Text = TotalHoursByDay.hoursThu.ToString();
            e.Row.Cells[(int)TimeSheetCells.HoursFri].Text = TotalHoursByDay.hoursFri.ToString();
            e.Row.Cells[(int)TimeSheetCells.HoursSat].Text = TotalHoursByDay.hoursSat.ToString();
            e.Row.Cells[(int)TimeSheetCells.HoursSun].Text = TotalHoursByDay.hoursSun.ToString();

            e.Row.Cells[(int)TimeSheetCells.HoursSun + 1].Text = (TotalHoursByDay.hoursMon +
                                                                TotalHoursByDay.hoursTue +
                                                                TotalHoursByDay.hoursWed +
                                                                TotalHoursByDay.hoursThu +
                                                                TotalHoursByDay.hoursFri +
                                                                TotalHoursByDay.hoursSat +
                                                                TotalHoursByDay.hoursSun).ToString();


        }
    }

    /// <summary>
    /// Put the page in add row mode
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void lnkAdd_Click(object sender, EventArgs e)
    {

        this.calWeek.SelectedDate = DateTime.Parse(this.SelectedDate);
        this.pnlAddRow.Visible = true;
        this.lblNoData.Text = string.Empty;
        this.grdTimesheet.Enabled = false;
        this.lnkExportToWord.Visible = false;
   
        //-- increment the new count that tells page_Init how many controls to add
        if (Session["AddNewRowCount"] != null)
        {
                Session["AddNewRowCount"] = int.Parse(Session["AddNewRowCount"].ToString()) + 1;
        }
        else
        {
            Session["AddNewRowCount"] = 1;
        }

    }


    /// <summary>
    /// Render the grid to word
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void lnkExport_Click(object sender, EventArgs e)
    {

        Vw_aspnet_HoursPivot_BO bo = new Vw_aspnet_HoursPivot_BO();
        DataTable dt= bo.SelectByWeekNum(this.WeekNum);
        WordExporter.GetWordOutput(dt, DateTime.Parse(this.lblMon.Text));

    }

    #endregion


    #region "Private Methods"


    /// <summary>
    /// Get the timesheeet data for the select week
    /// </summary>
    /// <returns></returns>
    private bool LoadGrid()
    {
        try
        {
            Vw_aspnet_HoursPivot_BO bo = new Vw_aspnet_HoursPivot_BO();

            this.grdTimesheet.DataSource = bo.SelectByWeekNum(this.WeekNum);
            this.grdTimesheet.DataBind();

            if (this.grdTimesheet.Rows.Count == 0)
            {
                pnlAddRow.Visible = false;
                this.lblNoData.Text = "No time has been entered for this week.  Click the Add link to enter hours.";

            }
            else
            {
                this.lblNoData.Text = string.Empty;
                this.lnkExportToWord.Visible = true;
            }

            GetDateLabels();
            this.grdTimesheet.Enabled = true;

            return true;
        }
        catch (Exception ex)
        {
            this.lblError.Visible = true;
            this.lblError.Text = ex.Message;
            return false;

        }
    }

    public void GetDateLabels()
    {

        DateTime selectedDate = this.calWeek.SelectedDate;
        double offset = this.GetOffset(selectedDate);

        this.lblMon.Text = string.Format("{0:MM/dd}", selectedDate.AddDays(-offset));
        this.lblTue.Text = string.Format("{0:MM/dd}", selectedDate.AddDays(-offset + 1));
        this.lblWed.Text = string.Format("{0:MM/dd}", selectedDate.AddDays(-offset + 2));
        this.lblThu.Text = string.Format("{0:MM/dd}", selectedDate.AddDays(-offset + 3));
        this.lblFri.Text = string.Format("{0:MM/dd}", selectedDate.AddDays(-offset + 4));
        this.lblSat.Text = string.Format("{0:MM/dd}", selectedDate.AddDays(-offset + 5));
        this.lblSun.Text = string.Format("{0:MM/dd}", selectedDate.AddDays(-offset + 6));

    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="date"></param>
    /// <returns></returns>
    protected int GetWeekNum(DateTime date)
    {

        // Gets the Calendar instance associated with a CultureInfo.
        System.Globalization.CultureInfo myCI = new System.Globalization.CultureInfo("en-US");
        System.Globalization.Calendar myCal = myCI.Calendar;

        // Gets the DTFI properties required by GetWeekOfYear.
        System.Globalization.CalendarWeekRule myCWR = myCI.DateTimeFormat.CalendarWeekRule;
        DayOfWeek myFirstDOW = myCI.DateTimeFormat.FirstDayOfWeek;

        // Trick the week num into counting Sunday as the last day of the Week
        if (date.DayOfWeek == DayOfWeek.Sunday)
            date = date.AddDays(-1);

        return myCal.GetWeekOfYear(date, myCWR, myFirstDOW);

    }


    /// <summary>
    /// Calculate the date offset so that the correct week is shown
    /// </summary>
    private double GetOffset(DateTime date)
    {

        double offset = 0;
        switch (date.DayOfWeek)
        {
            case (DayOfWeek.Monday):
                offset = 0;
                break;

            case (DayOfWeek.Tuesday):
                offset = 1;
                break;

            case (DayOfWeek.Wednesday):
                offset = 2;
                break;

            case (DayOfWeek.Thursday):
                offset = 3;
                break;

            case (DayOfWeek.Friday):
                offset = 4;
                break;

            case (DayOfWeek.Saturday):
                offset = 5;
                break;

            case (DayOfWeek.Sunday):
                offset = 6;
                break;
        }

        return offset;

    }


    private void AccumulateHours(UC_TimeSheetAddRow TimeSheetAddRow)
    {
        _HoursForThisWeek.hoursMon += TimeSheetAddRow.HoursForThisRow.hoursMon;
        _HoursForThisWeek.hoursTue += TimeSheetAddRow.HoursForThisRow.hoursTue;
        _HoursForThisWeek.hoursWed += TimeSheetAddRow.HoursForThisRow.hoursWed;
        _HoursForThisWeek.hoursThu += TimeSheetAddRow.HoursForThisRow.hoursThu;
        _HoursForThisWeek.hoursFri += TimeSheetAddRow.HoursForThisRow.hoursFri;
        _HoursForThisWeek.hoursSat += TimeSheetAddRow.HoursForThisRow.hoursSat;
        _HoursForThisWeek.hoursSun += TimeSheetAddRow.HoursForThisRow.hoursSun;
    }



    /// <summary>
    /// Check if the user has projects
    /// </summary>
    /// <param name="userName"></param>
    /// <returns></returns>
    private bool UserHasProjects(string userName)
    {
        List<Project> projects = Project.GetProjectsByUserName(userName);
        return (projects.Count > 0);
    }
    #endregion


    #region "Properties"
    private String _SelectedDate;
    public String SelectedDate
    {
        get
        {
            if (ViewState["SelectedDate"] != null)
            {
                _SelectedDate = ViewState["SelectedDate"].ToString();
            }
            return _SelectedDate;
        }
        set
        {
            ViewState["SelectedDate"] = value;
            _SelectedDate = value;
        }
    }

    private int _WeekNum;
    public int WeekNum
    {
        get
        {
            if (ViewState["WeekNum"] != null)
            {
                _WeekNum = int.Parse(ViewState["WeekNum"].ToString());
            }
            return _WeekNum;
        }
        set
        {
            ViewState["WeekNum"] = value;
            _WeekNum = value;
        }
    }

    public enum TimeSheetCells : int
    {
        CategoryName = 1,
        TimeEntryDescription = 2,
        HoursMon = 3,
        HoursTue = 4,
        HoursWed = 5,
        HoursThu = 6,
        HoursFri = 7,
        HoursSat = 8,
        HoursSun = 9,
    }

    private WeeklyHours _HoursForThisWeek;
    public WeeklyHours HoursForThisWeek
    {
        get
        {
            return _HoursForThisWeek;
        }
        set
        {
            _HoursForThisWeek = value;
        }
    }
#endregion
}
Avatar of CLoucas

ASKER

Thanks for this! I downloaded eWorld masked textbox and tried to compile the web control first, but I get errors regarding the ew tag prefix.  I have added both dlls in the project (eWorld.UI.dll and eWorld.UI.Compatibility.dll).  I get red sqeeglies under each reference of Numeric control following ew:.

Am I missing something?
Avatar of CLoucas

ASKER

I get several errors:
Error      9      Unknown server tag 'ew:NumericBox'.      C:\Documents and Settings\Chris\My Documents\Visual Studio 2005\WebSites\Timesheet\UC_TimeSheetAddRow.ascx      20      
Error      9      Element 'NumericBox' is not a known element. This can occur if there is a compilation error in the Web site.      C:\Documents and Settings\Chris\My Documents\Visual Studio 2005\WebSites\Timesheet\UC_TimeSheetAddRow.ascx      20      17      C:\...\Timesheet\

I also get the following error once:

Error      8      Could not load file or assembly 'eWorld.UI, Version=2.0.3.2310, Culture=neutral, PublicKeyToken=24d65337282035f2' or one of its dependencies. The system cannot find the file specified.      C:\Documents and Settings\Chris\My Documents\Visual Studio 2005\WebSites\Timesheet\UC_TimeSheetAddRow.ascx      4      
I think you have to add your own Register tag (my PublicKeyToken won't work on your system). Try dropping the control onto the aspx from the toolbox, and the tag should be different:

<%@ Register Assembly="eWorld.UI, Version=2.0.3.2310, Culture=neutral, PublicKeyToken=24d65337282035f2"
    Namespace="eWorld.UI" TagPrefix="ew" %>
Avatar of CLoucas

ASKER

Almost getting there!

I need the definition for WeeklyHours.....do you have that as a class somewhere?
Oops, sorry.  Here it is:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

/// <summary>
/// This class is a structure for the hours per day entered in the Timesheet
/// </summary>
public class WeeklyHours
{
      public WeeklyHours()
      {
            //
            // TODO: Add constructor logic here
            //
   
    }

    #region "Public Properties"
    private decimal _HoursMon=0;
    public decimal hoursMon
    {
        get
        {
            return _HoursMon;
        }
        set
        {
            _HoursMon = value;
        }
    }

    private decimal _HoursTue=0;
    public decimal hoursTue
    {
        get
        {
            return _HoursTue;
        }
        set
        {
            _HoursTue = value;
        }
    }

    private decimal _HoursWed=0;
    public decimal hoursWed
    {
        get
        {
            return _HoursWed;
        }
        set
        {
            _HoursWed = value;
        }
    }

    private decimal _HoursThu=0;
    public decimal hoursThu
    {
        get
        {
            return _HoursThu;
        }
        set
        {
            _HoursThu = value;
        }
    }

    private decimal _HoursFri=0;
    public decimal hoursFri
    {
        get
        {
            return _HoursFri;
        }
        set
        {
            _HoursFri = value;
        }
    }

    private decimal _HoursSat=0;
    public decimal hoursSat
    {
        get
        {
            return _HoursSat;
        }
        set
        {
            _HoursSat = value;
        }
    }

    private decimal _HoursSun=0;
    public decimal hoursSun
    {
        get
        {
            return _HoursSun;
        }
        set
        {
            _HoursSun = value;
        }
    }

    public Decimal GetTotalHours()
    {

        return hoursMon +
                hoursTue +
                hoursWed +
                hoursThu +
                hoursFri +
                hoursSat +
                hoursSun;

    }
    #endregion
}
Avatar of CLoucas

ASKER

Sorry for being a pain, but I now need a reference for Vw_aspnet_HoursPivot_BO, WordExporter
Get rid of this method --it's used to render a word report:

protected void lnkExport_Click(object sender, EventArgs e)
    {

        Vw_aspnet_HoursPivot_BO bo = new Vw_aspnet_HoursPivot_BO();
        DataTable dt= bo.SelectByWeekNum(this.WeekNum);
        WordExporter.GetWordOutput(dt, DateTime.Parse(this.lblMon.Text));

    }
Avatar of CLoucas

ASKER

ok done with that, what about Vw_aspnet_HoursPivot_BO?  that's been referenced in a few other places...should i take that out too?
Oops, the page is not much good without data.  To get the time entries in a weekly view, I had create a view in the database:

SELECT DISTINCT
                      TOP (100) PERCENT dbo.aspnet_starterkits_TimeEntry.TimeEntryDescription, dbo.aspnet_starterkits_TimeEntry.CategoryId,
                      dbo.aspnet_starterkits_TimeEntry.TimeEntryCreatorId, dbo.aspnet_starterkits_TimeEntry.TimeEntryUserId, CASE (DATENAME(weekday,
                      [TimeEntryDate])) WHEN 'Monday' THEN SUM([TimeEntryDuration]) ELSE 0 END AS Mon, CASE (DATENAME(weekday, [TimeEntryDate]))
                      WHEN 'Tuesday' THEN SUM([TimeEntryDuration]) ELSE 0 END AS Tue, CASE (DATENAME(weekday, [TimeEntryDate]))
                      WHEN 'Wednesday' THEN SUM([TimeEntryDuration]) ELSE 0 END AS Wed, CASE (DATENAME(weekday, [TimeEntryDate]))
                      WHEN 'Thursday' THEN SUM([TimeEntryDuration]) ELSE 0 END AS Thu, CASE (DATENAME(weekday, [TimeEntryDate]))
                      WHEN 'Friday' THEN SUM([TimeEntryDuration]) ELSE 0 END AS Fri, CASE (DATENAME(weekday, [TimeEntryDate]))
                      WHEN 'Saturday' THEN SUM([TimeEntryDuration]) ELSE 0 END AS Sat, CASE (DATENAME(weekday, [TimeEntryDate]))
                      WHEN 'Sunday' THEN SUM([TimeEntryDuration]) ELSE 0 END AS Sun, dbo.aspnet_starterkits_TimeEntry.TimeEntryId, DATEPART(wk,
                      dbo.aspnet_starterkits_TimeEntry.TimeEntryDate) AS WeekNum, dbo.aspnet_starterkits_ProjectCategories.CategoryName,
                      dbo.aspnet_starterkits_Projects.ProjectName
FROM         dbo.aspnet_starterkits_TimeEntry INNER JOIN
                      dbo.aspnet_starterkits_ProjectCategories ON
                      dbo.aspnet_starterkits_TimeEntry.CategoryId = dbo.aspnet_starterkits_ProjectCategories.CategoryId INNER JOIN
                      dbo.aspnet_starterkits_Projects ON dbo.aspnet_starterkits_ProjectCategories.ProjectId = dbo.aspnet_starterkits_Projects.ProjectId
GROUP BY dbo.aspnet_starterkits_TimeEntry.TimeEntryDuration, dbo.aspnet_starterkits_TimeEntry.TimeEntryDescription,
                      dbo.aspnet_starterkits_TimeEntry.CategoryId, dbo.aspnet_starterkits_TimeEntry.TimeEntryDate, dbo.aspnet_starterkits_TimeEntry.TimeEntryCreatorId,
                      dbo.aspnet_starterkits_TimeEntry.TimeEntryUserId, dbo.aspnet_starterkits_TimeEntry.TimeEntryId,
                      dbo.aspnet_starterkits_ProjectCategories.CategoryName, dbo.aspnet_starterkits_Projects.ProjectName
ORDER BY dbo.aspnet_starterkits_TimeEntry.TimeEntryId
ASKER CERTIFIED SOLUTION
Avatar of kraffay
kraffay

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial