Sample Project

The sample project includes:

  • DayPilot Lite 3.2.247
  • C# Source Code
  • VB.NET Source Code
  • Visual Studio 2010/Visual Studio 2012 Solution
  • SQL Server database

Online Demo

Requirements

  • .NET Framework 4.0 or higher
  • Visual Studio 2010/Visual Studio 2012
  • Microsoft SQL Server 2008+ (Express)/ Microsoft SQL Server 2012 + (LocalCB)

License

The source code of this sample project is licensed under the Apache Software License 2.0.

Features

This sample project management ASP.NET application allows to create fast project time to completion estimate. It displays a project overview using a Gantt chart. Resource schedule and availability is displayed in a Resources view.

See also related tutorials on Gantt chart:

This project uses the basic Gantt chart from DayPilot Lite (open-source).

Features:

  • Visual project management
  • Plan overview in a Gantt chart
  • Multiple projects supported
  • Resource utilization/availability
  • Task tracking in real time
  • Task status (planned, started, finished)
  • Setting task priority using drag&drop
  • Estimated time to completion

Advanced Gantt Chart Control

More advanced features can be found in the ASP.NET Gantt Chart control in DayPilot Pro (commercial):

asp.net-gantt-chart-control-advanced.png

See also the DayPilot Pro Gantt Chart tutorial:

Gantt Chart (Tasks)

project-management-asp-net-gantt.png

The main view is based on DayPilot Scheduler Lite in Gantt mode.

Task Header

project-management-asp-net-task-row.png

The task header is customized using BeforeResHeaderRender event:

  • Status-indicating icon (blue/green/orange)
  • Additional column data (estimated, spent, resource)
protected void DayPilotScheduler1_BeforeResHeaderRender(object sender, BeforeHeaderRenderEventArgs e)
{
  DataItemWrapper task = e.DataItem;

  string name = (string)task["AssignmentNote"];
  int id = Convert.ToInt32(task["AssignmentId"]);
  string resource = Convert.ToString(task["ResourceName"]);
  string status = Convert.ToString(task["AssignmentStatus"]);

  TimeSpan duration = TimeSpan.FromMinutes(Convert.ToInt32(task["AssignmentDuration"]));

  string durationString = duration.ToHourMinuteString();
  string spentString = Binder.Get(task, "AssignmentDurationReal").IsNotNull ? Binder.Get(task, "AssignmentDurationReal").TimeSpanFromMinutes.ToHourMinuteString() : String.Empty;

  e.InnerHTML = TaskLink(name, id, status);
  e.Columns[0].InnerHTML = "<div style='text-align:right'>" + durationString + "</div>";
  e.Columns[1].InnerHTML = "<div style='text-align:right'>" + spentString + "</div>";
  e.Columns[2].InnerHTML = resource;
}

Timeline and Time to Completion (TTC) Calculation

project-management-asp-net-timeline.png

Calculation is done using Plan class:

 DataTable table = new DataManager().GetAssignmentsPlanned(ProjectId);

_plan = new Plan();
_plan.LoadTasks(table.Rows, "AssignmentId", "AssignmentDuration", "ResourceId");
_plan.Process(); 

The Plan class arranges the tasks into groups by resource and arranges them into a timeline. It takes the business hours (8-17) and weekends (Saturday, Sunday) into account. 

All events are added to a single List.

 private List<Task> Data
{
  get
  {
    List<Task> all = new List<Task>();
    if (!CheckBoxHideFinished.Checked)
    {
      all.AddRange(Finished);
    }
    all.AddRange(Started);
    all.AddRange(Plan.Processed);
    return all;
  }
}

The resulting List is passed to DayPilot Scheduler (DataSource property) to be displayed in the Gantt chart:

 private void LoadEvents()
{
  DayPilotScheduler1.DataSource = Data;
  DataBind();
}

Task Reordering (Drag & Drop)

project-management-asp-net-task-ordering-drag-drop.png

The task start dates are not fixed. Instead, a dynamic schedule is calculated and updated every time you display the Gantt chart.

You can set the priorities by dragging the planned (blue) tasks up or down.

The drag&drop reordering is implemented using jQuery:

    function init() {
        $(document).ready(function () {
            $(".task_status.planned")
            .css("cursor", "move")
            .attr('unselectable', 'on')
            .css('user-select', 'none')
            .css('-webkit-user-select', 'none')
            .css('-moz-user-select', 'none')
            .each(function () {
                this.onselectstart = function (e) { if (e && e.preventDefault) e.preventDefault(); return false; };
            });
            $(".task_status.planned").mousedown(function (e) {
                var id = $(this).data("taskid");
                drag.active = true;
                drag.id = id;
                drag.start = DayPilot.mo3($("#dps")[0], e.originalEvent);
                drag.source = $(this);

                var div = document.createElement("div");
                div.style.position = "absolute";
                div.style.height = "2px";
                div.style.width = "60px";
                div.style.backgroundColor = "red";
                div.style.display = "none";
                div.style.userSelect = "none";
                div.style.webkitUserSelect = "none";
                div.style.MozUserSelect = "none";
                div.setAttribute("unselectable", "on");
                $("#dps")[0].appendChild(div);
                $(document.body).addClass("moving");

                drag.div = div;
            });
            $(document).mousemove(function (e) {
                if (!drag.active) {
                    return;
                }
                drag.source.parent().css({ opacity: 0.5 });

                var rowHeight = 20;
                var headerHeight = 20;
                var coords = DayPilot.mo3($("#dps")[0], e.originalEvent);
                drag.position = Math.floor((coords.y - headerHeight) / rowHeight);
                drag.position = Math.max(0, drag.position);

                var offset = {};
                offset.top = 0;
                offset.left = 0;
                drag.div.style.top = (offset.top + rowHeight * drag.position + headerHeight) + "px";
                drag.div.style.left = offset.left + "px";
                drag.div.style.display = "";
            });
            $(document).mouseup(function () {
                if (!drag.active) {
                    return;
                }

                if (drag.div && drag.div.parentNode) {
                    drag.div.parentNode.removeChild(drag.div);
                }
                $(document.body).removeClass("moving");

                var order = [];
                var placed = false;
                $(".task_status").each(function (index) {
                    if (!$(this).hasClass("planned")) {
                        return;
                    }
                    var id = $(this).data("taskid");
                    //alert("id:" + id);

                    if (index == drag.position) {
                        order.push(drag.id);
                        placed = true;
                    }

                    if (id == drag.id) {
                        return;
                    }
                    order.push(id);
                });

                if (!placed) {
                    order.push(drag.id);
                }

                //alert("new order:" + order.join(","));
                updateOrder(order.join(','));

                drag = {};
            });
        });
    }

Adding New Tasks

project-management-asp-net-add-task.png

The new task popup is displayed using DayPilot.Modal dialog (open-source).

<div class="space">
  <a href="javascript:create('<%# DateTime.Today.ToString("s") %>')" class="button">New task</a>
</div>

JavaScript:

function create(start, end, resource) {
    createModal().showUrl(id.root + 'Project/New.aspx/' + id.project + '?start=' + start + "&end=" + end + "&resource=" + resource);
}

function edit(taskId) {
    createModal().setHeight(300).showUrl(id.root + 'Project/Edit.aspx/' + id.project + '?id=' + taskId);
}

function createModal() {
    var modal = new DayPilot.Modal();
    modal.top = 60;
    modal.width = 300;
    modal.opacity = 50;
    modal.border = "10px solid #d0d0d0";
    modal.closed = function () {
        if (this.result && this.result.refresh) {
            __doPostBack(id.refreshButton, '');
        }
    };

    modal.setHeight = function (height) {
        modal.height = height;
        return modal;
    };

    modal.height = 260;
    modal.zIndex = 100;

    return modal;
}

Task Status

project-management-asp-net-task-status.png

The task status can be set to one of the following values:

  • planned
  • started
  • finished

The time spent can be updated manually at any time.

If you don't specify the time spent on the task, it will be calculated automatically when the status is set to finished:

  • If the task was started manually it will use the real time between start and finish.
  • If the previous status was "planned" it will use the estimated time.

Planned Task

project-management-asp-net-task-planned.png

Started Task

Note the time summary below the form.

project-management-asp-net-task-started.png

Finished Task

Note the start and end time of the task.

project-management-asp-net-task-finished.png

Resources View

project-management-asp-net-resources.png

You can also define a set of resources (people) and assign them to the tasks. The resources can be arranged in groups.

The resources view will display the schedule for each of the resource.

private void CreateResources()
{
  DayPilotScheduler1.Resources.Clear();

  AddDefaultGroup();

  foreach (DataRow dr in Groups.Rows)
  {
    string name = (string) dr["GroupName"];
    int id = Convert.ToInt32(dr["GroupId"]);

    string html = table(name, 0);
    DayPilotScheduler1.Resources.Add(new Resource(html, "GROUP"));

    AddChildren(id);
  }
}

See Also