Project Management
A Gantt chart for Windows Forms: a task list beside a timeline of bars, summary brackets, milestones and dependency arrows, scheduled by the critical-path method and edited with the mouse or entirely from the keyboard.
Assembly
| Assembly | Binarymission.WinForms.Controls.ProjectManagement.dll |
| Root namespace | Binarymission.WinForms.Controls.ProjectManagement |
| Target frameworks | .NET Framework 4.8, .NET 6 / 8 / 10 |
Overview
What it is for
Use it wherever people plan work against dates: a project plan, a release schedule, a production run, a fit-out programme. The task list on the left is a tree grid – outline number, name, dates, length, progress, assignee and predecessors – and the timeline on the right shows each task as a bar on the calendar, with weekends and holidays shaded, a line at today and the critical path picked out in its own colour. A splitter between the two moves the boundary.
The plan
Give the chart a list of ProjectTask objects in Tasks and the
dependencies between them as TaskLink objects in Links. A task becomes
a summary when other tasks name it as their ProjectTask.ParentId, and a milestone
when its duration is zero. The chart never keeps dates of its own: it schedules the plan on the
working calendar of ProjectStart, WorkingWeek and
Holidays (see ProjectScheduler) and draws the result, which
Schedule returns. Data that cannot be used – a duplicate id, a link to a missing task,
a loop – is reported in ProjectSchedule.Problems, and everything else is still
drawn.
Use an ObservableCollection or a
BindingList for the two lists and the chart watches them and
every object in them: add a task, change a duration, and the chart schedules again and redraws.
Give the same two collections to a PertChart and a TaskBoard and all
three show one plan; an edit made in any of them is seen by the others at once.
Editing
A reader can drag a bar to move it, drag its end to change its length, drag the small
triangle under it to record progress, and drag from the dot at its end to another bar to link the
two. A slow second click on a cell, or F2, edits it: the name, the start, the length, the progress,
or the predecessors, typed as a planner writes them (2, 3SS+1). Every edit is offered first
through the cancelable TaskChanging or LinksChanging event, then
written to the task or link objects themselves, then announced by TaskChanged or
LinksChanged – so an application enforces its own rules in one handler, whichever way
the edit was made. ReadOnly turns editing off.
Keyboard
| Keys | Action |
|---|---|
Up, Down, Home, End, Page Up, Page Down | Move between rows. |
Left, Right | Move between the editable cells of the row; at the name, close and open a summary or go to its parent. |
Shift+Left, Shift+Right | Move the selected task a working day earlier or later. |
Ctrl+Shift+Left, Ctrl+Shift+Right | Shorten or lengthen the selected task by a working day. |
Ctrl+Left, Ctrl+Right | Scroll the timeline. |
Plus, Minus | Open and close the selected summary. |
Ctrl+Plus, Ctrl+Minus | Zoom in and out. |
F2 | Edit the current cell; Enter commits, Tab moves to the next editable cell, Esc cancels. |
Enter, Space | Raise |
Delete | Remove the selected link. |
Esc | Cancel a drag in progress. |
The wheel scrolls the rows, with Shift scrolls sideways, and with Ctrl zooms about the date under the pointer. Each row is exposed to screen readers as an outline item that says the task's dates, length, progress and whether it is critical.
Appearance
The bars, the critical path, summaries, baselines and the today line each have a colour of
their own (BarColor, CriticalBarColor and so on). The grid lines,
weekend shading, links and headers default to shades worked out from
Control.ForeColor and BackColor, so setting those two for a dark theme
gives a dark chart. In Windows high-contrast mode the system colours are used instead. The
timeline's scale is Zoom; every size is in logical pixels (1/96 inch) and scales
with the display. ExportImage and CreatePrintDocument draw the whole
plan as an image or across printed pages.
Getting started
A form showing an eight-task website plan, with the assignee and progress columns added, a rule that finished work cannot be moved, and the finish date in the title bar. On a Monday-to-Friday week from 2 November 2026 the plan finishes on 1 December 2026, and the critical path runs through the brief, the wireframes, the front end, testing and go-live.
using System;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Windows.Forms;
using Binarymission.WinForms.Controls.ProjectManagement;
public sealed class PlanForm : Form
{
private readonly GanttChart _gantt = new GanttChart();
private readonly ObservableCollection<ProjectTask> _tasks = new ObservableCollection<ProjectTask>();
private readonly ObservableCollection<TaskLink> _links = new ObservableCollection<TaskLink>();
public PlanForm()
{
Text = "Website relaunch";
Size = new Size(1100, 520);
_tasks.Add(new ProjectTask("design", "Design"));
_tasks.Add(new ProjectTask("brief", "Agree the brief", 3) { ParentId = "design", Assignee = "Priya", Progress = 100 });
_tasks.Add(new ProjectTask("wire", "Wireframes", 5) { ParentId = "design", Assignee = "Priya", Progress = 40 });
_tasks.Add(new ProjectTask("build", "Build"));
_tasks.Add(new ProjectTask("front", "Front end", 10) { ParentId = "build", Assignee = "Tom" });
_tasks.Add(new ProjectTask("api", "Order API", 8) { ParentId = "build", Assignee = "Aisha" });
_tasks.Add(new ProjectTask("test", "User testing", 4) { Assignee = "Priya" });
_tasks.Add(new ProjectTask("live", "Go live", 0));
_links.Add(new TaskLink("brief", "wire"));
_links.Add(new TaskLink("wire", "front"));
_links.Add(new TaskLink("wire", "api", TaskLinkType.StartToStart, 2));
_links.Add(new TaskLink("build", "test"));
_links.Add(new TaskLink("test", "live"));
_gantt.Dock = DockStyle.Fill;
_gantt.Tasks = _tasks;
_gantt.Links = _links;
_gantt.ProjectStart = new DateTime(2026, 11, 2);
_gantt.Holidays.Add(new DateTime(2026, 12, 25));
_gantt.Columns = GanttColumns.Default | GanttColumns.Assignee | GanttColumns.Progress;
_gantt.TaskChanging += OnTaskChanging;
_gantt.ScheduleChanged += (sender, e) => ShowFinish();
Controls.Add(_gantt);
Load += (sender, e) =>
{
ShowFinish();
_gantt.ZoomToFit();
};
}
private void OnTaskChanging(object sender, TaskChangingEventArgs e)
{
// Finished work stays where it is; its name can still be corrected.
if (e.Task.Progress >= 100 && (e.NewStart.HasValue || e.NewDuration.HasValue))
e.Cancel = true;
}
private void ShowFinish()
{
Text = "Website relaunch - finishes " + _gantt.Schedule.ProjectFinish.ToString("d MMM yyyy");
}
}API reference
Binarymission.WinForms.Controls.ProjectManagement
class BoardColumn | A column of the task board: one value of Status, the heading shown for it, and the most cards it should hold. |
enum BoardLaneBy | What the task board splits its rows - its lanes - by: nothing, the assignee, the category, or the phase (top-level summary task) each piece of work belongs to. |
class CardMovingEventArgs | Provides data for the task board's CardMoving event: a card about to move to another column, lane or position, which a handler can inspect and refuse. |
class GanttChart | A Gantt chart for Windows Forms: a task list beside a timeline of bars, summary brackets, milestones and dependency arrows, scheduled by the critical-path method and edited with the mouse or entirely from the keyboard. |
enum GanttColumns | The columns of the Gantt chart's task list, as flags that combine. The task's name is always shown. |
enum GanttZoom | How much time the Gantt chart's timeline shows, from a column per day to a column per half-year. |
class LinksChangingEventArgs | Provides data for the Gantt chart's LinksChanging event: links the reader is about to add to the plan or remove from it, all leading into one task. |
class PertChart | A PERT chart for Windows Forms: a plan's work drawn as a network of boxes joined in the order it has to happen, each box carrying its earliest and latest dates and its float, with the critical path picked out. |
class ProjectSchedule | A plan as scheduled: every task's dates and float, the links that were honoured, the critical path, the project's start and finish, and anything in the input that could not be used. |
class ProjectScheduler | Schedules a project plan by the critical-path method: works out every task's earliest and latest dates on a working calendar, its float, and the chain of tasks that decides when the plan finishes. |
class ProjectTask | One row of a project plan - a piece of work, a summary that groups other tasks, or a milestone - as the Gantt chart, the PERT chart and the task board all read it. |
class ScheduleInput | Everything Schedule(ScheduleInput) needs to schedule a plan: the tasks, the links between them, the project's first day and the working calendar. |
class ScheduleProblem | Something in a plan that could not be used as written: a duplicate id, a link to a missing task, a loop of links. The scheduler never throws for bad data; it reports it here, leaves it out, and schedules everything else. |
enum ScheduleProblemKind | What kind of problem the scheduler found in a plan. Each kind says what was wrong and what was done about it, so that the rest of the plan could still be scheduled. |
class ScheduledLink | One link as the scheduler used it. Links that could not be honoured are not here; they are in Problems instead. |
class ScheduledTask | One task as scheduled: the dates the links allow, how much it can slip, whether it is critical, and where it sits in the outline. |
class TaskBoard | A task board for Windows Forms: a plan's work as cards in workflow columns, optionally split into lanes by assignee, category or phase, moved by dragging or entirely from the keyboard. |
class TaskChangingEventArgs | Provides data for the Gantt chart's TaskChanging event: a change the reader is about to make to one task, which a handler can inspect and refuse. |
enum TaskConstraintKind | How a task's own planned date holds it, in addition to its links: as the earliest it may start, as a date it must start on, or as the earliest it may finish. |
enum TaskEditSource | How a change to the plan was made: with the pointer, the keyboard, by typing in a cell, or by the application. |
class TaskEventArgs | Provides data for the events that concern one task: a task changed, activated, opened or closed, or a card moved. |
class TaskLink | A dependency between two tasks: the successor (ToId) waits for the predecessor (FromId) in the way Type says, give or take Lag working days. |
enum TaskLinkType | Which end of the predecessor a link waits for, and which end of the successor it holds: the four dependency types of the critical-path method. |
class WorkCalendar | A working calendar: which days of the week are worked and which dates are not, and the conversion between calendar dates and the count of working days the scheduler plans in. |
enum WorkingWeek | The days of the week that are worked, as flags that combine, so a whole working week is one property value: WorkingWeek.Monday | WorkingWeek.Tuesday | WorkingWeek.Wednesday | WorkingWeek.Thursday for a four-day week. |