HypernovaDesktop Components · docs
Binarymission
WinForms › Project Management › PertChart

PertChart

class.NET 6 / 8 / 10.NET Framework 4.8Binarymission.WinForms.Controls.ProjectManagement

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.

public partial class PertChart : Control

Inherits from / implements: Control

Remarks

What it is for

A Gantt chart answers "when?"; a PERT chart answers "what has to happen first?". Use it to review a plan's logic – which tasks hold others up, where the slack is, and which chain of work decides the finish date – and alongside a GanttChart or a TaskBoard as another view of the same plan.

The plan

Give the chart the same Tasks and Links as a GanttChart or a TaskBoard and the three show one plan: a change made in either of the others is drawn here at once. The plan is scheduled on the calendar of ProjectStart, WorkingWeek and Holidays, exactly as the other charts schedule it, and Schedule returns the result.

Summary tasks are structure, not work, so they have no box; a link into a summary is drawn to each subtask inside it that nothing else inside waits for, and a link out of one from each subtask that nothing else inside follows.

Reading a box

Each box has the task's name across its top (with a diamond before it for a milestone); under it, its earliest start, its length in working days and its earliest finish; under those, its latest start, its float and its latest finish; and along the bottom a bar showing its progress. Boxes are placed in columns by the longest chain of links before them, so every arrow runs forward, and are ordered within a column to sit level with the boxes they link to. While ShowCriticalPath is on, critical boxes and the links between them are drawn in CriticalColor with heavier lines.

Using it

The chart is for reading: it never changes the plan. Click a box or use the arrow keys to select it – Right goes to what follows, Left to what came before, Up and Down along a column, Home and End to the first and last box – and press Enter or double-click to raise TaskActivated. Drag the background to pan, use the wheel to scroll (with Shift, sideways), and zoom with Ctrl and the wheel about the pointer, or with Ctrl and Plus, Minus or 0 (back to full size). Each box is exposed to screen readers with its dates, its float and what it follows and leads to, so the plan's logic can be followed without seeing the arrows. In a right-to-left layout the network runs right to left, and so do the arrow keys.

Examples

A form's constructor that shows a Gantt chart and a PERT chart of one plan, one above the other, keeping their selections in step. tasks and links are observable collections such as those built in the GanttChart example.

using System;
using System.Windows.Forms;
using Binarymission.WinForms.Controls.ProjectManagement;

SplitContainer split = new SplitContainer { Dock = DockStyle.Fill, Orientation = Orientation.Horizontal };

GanttChart gantt = new GanttChart { Dock = DockStyle.Fill, Tasks = tasks, Links = links };
PertChart network = new PertChart
{
    Dock = DockStyle.Fill,
    Tasks = tasks,
    Links = links,
    NodeWidth = 200,
    ColumnGap = 56
};

// Both charts are given the same project start, so they schedule the same dates.
gantt.ProjectStart = network.ProjectStart = new DateTime(2026, 11, 2);

// Selecting a task in either chart selects it in the other.
gantt.SelectedTaskChanged += (sender, e) => network.SelectedTask = gantt.SelectedTask;
network.SelectedTaskChanged += (sender, e) =>
{
    if (network.SelectedTask != null)
        gantt.SelectedTask = network.SelectedTask;
};

split.Panel1.Controls.Add(gantt);
split.Panel2.Controls.Add(network);
Controls.Add(split);

Shown += (sender, e) => network.ZoomToFit();

See also

Members at a glance

Constructors
PertChartCreates a PERT chart with an empty plan: empty, watched Tasks, Links and Holidays collections and a Monday-to-Friday week, on the system's window colours.
Properties
BoxBackColorGets or sets the fill of a box.
BoxBorderColorGets or sets the border of a box that is not critical, and (blended with the fill) the lines dividing a box into its parts.
ColumnGapGets or sets the space between one column of boxes and the next, where the arrows run.
ConnectorColorGets or sets the colour of the arrows between boxes that are not critical.
CriticalColorGets or sets the colour of a critical box's border, of the arrows between critical boxes, and of a critical box's float; a tint of it fills a critical box's name.
HolidaysGets or sets the dates that are not worked, such as public holidays.
LinksGets or sets the dependencies between the tasks: the arrows between the boxes.
NodeHeightGets or sets the height of a box.
NodeWidthGets or sets the width of a box.
ProgressColorGets or sets the colour of the bar along the bottom of a box that shows how far its task has got, and of the diamond of a milestone that is not critical.
ProjectStartGets or sets the first day work can happen. No task is scheduled before it, except one that must start on an earlier date.
RowGapGets or sets the space between one row of boxes and the next, where arrows that pass several columns run.
SelectedTaskGets or sets the task whose box is selected.
ShowCriticalPathGets or sets whether the critical path – the boxes and links that cannot slip without moving the finish – is drawn in CriticalColor with heavier lines.
TasksGets or sets the tasks of the plan, as a flat list with parent references.
TodayGets or sets the date the charts treat as today.
WorkingWeekGets or sets the days of the week that are worked. Durations and lags count only these days.
ZoomFactorGets or sets how large the network is drawn, as a multiple of its natural size.
Methods
CreateAccessibilityInstanceCreates the accessible object that presents the chart to screen readers and other assistive technology as a list: one item per box, saying the task's dates and float and what it follows and leads to.
DisposeStops watching the plan and releases the fonts and the tooltip the chart created.
EnsureScheduleGets the plan as the chart has scheduled it: every task's dates and float, the links that were honoured, the critical path, and anything in the plan that could not be used.
ExportImageDraws the whole network into a new image, at its natural size: 96 DPI and a ZoomFactor of 1, whatever the screen is showing.
IsInputKeyClaims the keys the chart uses for itself, so that the form does not take them for moving the focus or pressing a button.
OnDpiChangedAfterParentRebuilds everything measured in device pixels when the chart moves to a display with a different scale: the fonts, the scroll bars and the scroll range.
OnFontChangedRaises Control.FontChanged and rebuilds the fonts the boxes are written in.
OnGotFocusDraws the focus cue and announces the selected box to screen readers.
OnHandleCreatedFits the scroll bars once the window exists and the display's scale is known for certain, and schedules any changes made before then.
OnHandleDestroyedForgets a refresh posted to a window that is going away; the next window posts again.
OnKeyDownRaises Control.KeyDown, then, unless a handler has handled the key, carries out the chart's keyboard commands: the arrows move the selection along the work (Right to what follows, Left to what came before, Up and Down along a column), Home and End go to the first and last box, Page Up and Page Down scroll, Enter raises TaskActivated, and Ctrl with Plus, Minus or 0 zooms in, out, or back to full size.
OnLostFocusRemoves the focus cue.
OnMouseCaptureChangedEnds a pan when the mouse is taken away part way through, by a message box or a switch of window.
OnMouseDoubleClickRaises Control.MouseDoubleClick, then raises TaskActivated when the double-click was on a box.
OnMouseDownRaises Control.MouseDown, takes the focus, and with the left button selects the box under the pointer, or starts panning when the press is on the background.
OnMouseLeaveRaises Control.MouseLeave and hides the tooltip.
OnMouseMoveRaises Control.MouseMove, then pans while the background is dragged; otherwise shows the tooltip and the hand pointer over a box.
OnMouseUpRaises Control.MouseUp and ends a pan.
OnMouseWheelRaises Control.MouseWheel, then scrolls the network up and down; with Shift, sideways; with Ctrl, zooms about the point under the pointer.
OnPaintRaises Control.Paint, then draws the arrows, the boxes and the focus cue. A fault while drawing is absorbed rather than leaving the control crossed out, and the next paint tries again.
OnResizeRaises Control.Resize and fits the scroll bars and the view to the new size.
OnRightToLeftChangedRaises Control.RightToLeftChanged and lays the network out again mirrored, so the work runs from right to left, scrolled to its start.
OnScheduleChangedRaises the ScheduleChanged event.
OnSelectedTaskChangedRaises the SelectedTaskChanged event.
OnTaskActivatedRaises the TaskActivated event.
OnZoomFactorChangedRaises the ZoomFactorChanged event.
RescheduleSchedules the plan and lays the network out again now, and raises ScheduleChanged.
ScrollToTaskScrolls the chart until a task's box is in view, with a little space around it.
ZoomToFitSets ZoomFactor so that the whole network fits the control, and scrolls to its start.
Events
ScheduleChangedOccurs after the plan has been scheduled again because something changed: a task, a link, a collection, a calendar setting, or a call to Reschedule.
SelectedTaskChangedOccurs when the selected box changes: by the reader, by setting SelectedTask, or because the selected task left the plan.
TaskActivatedOccurs when the reader double-clicks a box or presses Enter with a box selected: the moment to open the application's own view of the task.
ZoomFactorChangedOccurs when ZoomFactor changes, by the property, ZoomToFit, Ctrl and the wheel, or Ctrl and Plus, Minus or 0.

Constructors

PertChart

public PertChart()

Creates a PERT chart with an empty plan: empty, watched Tasks, Links and Holidays collections and a Monday-to-Friday week, on the system's window colours.

Properties

BoxBackColor

public Color BoxBackColor

Gets or sets the fill of a box.

Value
The default is Color.Empty, a fill a shade away from Control.BackColor towards Control.ForeColor.
Designer category
Appearance
Remarks

In Windows high-contrast mode the system colours are used instead.

BoxBorderColor

public Color BoxBorderColor

Gets or sets the border of a box that is not critical, and (blended with the fill) the lines dividing a box into its parts.

Value
The default is Color.Empty, a shade between Control.BackColor and Control.ForeColor.
Designer category
Appearance
Remarks

In Windows high-contrast mode the system colours are used instead.

ColumnGap

public int ColumnGap

Gets or sets the space between one column of boxes and the next, where the arrows run.

Value
In logical pixels (1/96 inch), scaled with the display and ZoomFactor. The default is 64; a smaller value than 24 is raised to 24.
Default
DefaultColumnGap
Designer category
Layout

ConnectorColor

public Color ConnectorColor

Gets or sets the colour of the arrows between boxes that are not critical.

Value
The default is Color.Empty, a shade between Control.BackColor and Control.ForeColor.
Designer category
Appearance
Remarks

In Windows high-contrast mode the system colours are used instead.

CriticalColor

public Color CriticalColor

Gets or sets the colour of a critical box's border, of the arrows between critical boxes, and of a critical box's float; a tint of it fills a critical box's name.

Value
The default is a red-orange, RGB 224, 82, 43.
Designer category
Appearance
Remarks

Used only while ShowCriticalPath is on. Setting Color.Empty returns to the default. In Windows high-contrast mode the system colours are used instead.

Holidays

public IList<DateTime> Holidays

Gets or sets the dates that are not worked, such as public holidays.

Value
Dates; only their date part is read. Never null: the chart starts with an empty ObservableCollection, and setting null gives a new empty one.
Remarks

Durations and lags skip these dates. An observable collection is watched; after changing a plain list, call Reschedule.

NodeHeight

public int NodeHeight

Gets or sets the height of a box.

Value
In logical pixels (1/96 inch), scaled with the display and ZoomFactor. The default is 92; a smaller value than 48 is raised to 48.
Default
DefaultNodeHeight
Designer category
Layout

NodeWidth

public int NodeWidth

Gets or sets the width of a box.

Value
In logical pixels (1/96 inch), scaled with the display and ZoomFactor. The default is 188; a smaller value than 80 is raised to 80.
Default
DefaultNodeWidth
Designer category
Layout
Remarks

Long names are cut short with an ellipsis; widen the boxes for a plan with long task names.

ProgressColor

public Color ProgressColor

Gets or sets the colour of the bar along the bottom of a box that shows how far its task has got, and of the diamond of a milestone that is not critical.

Value
The default is a calm blue, RGB 59, 125, 216.
Designer category
Appearance
Remarks

Setting Color.Empty returns to the default. In Windows high-contrast mode the system colours are used instead.

ProjectStart

public DateTime? ProjectStart

Gets or sets the first day work can happen. No task is scheduled before it, except one that must start on an earlier date.

Value
A date; only its date part is kept, and a day that is not worked is moved to the next working day. The default is null, which takes the earliest planned ProjectTask.Start in the plan, then the earliest planned ProjectTask.Finish, and failing both, today's date.
Default
null
Designer category
Plan
Remarks

Give every chart showing a plan the same value, so that they schedule the same dates.

RowGap

public int RowGap

Gets or sets the space between one row of boxes and the next, where arrows that pass several columns run.

Value
In logical pixels (1/96 inch), scaled with the display and ZoomFactor. The default is 28; a smaller value than 8 is raised to 8.
Default
DefaultRowGap
Designer category
Layout

SelectedTask

public ProjectTask SelectedTask

Gets or sets the task whose box is selected.

Value
A task in Tasks, or null (the default) when no box is selected.
Remarks

Setting a task scrolls its box into view, and raises SelectedTaskChanged when the selection changes. Setting a task that has no box – a summary, or a task not in the plan – clears the selection. When the selected task leaves the plan, the selection is cleared and SelectedTaskChanged is raised from the message loop.

ShowCriticalPath

public bool ShowCriticalPath

Gets or sets whether the critical path – the boxes and links that cannot slip without moving the finish – is drawn in CriticalColor with heavier lines.

Value
true (the default) to pick out the critical path.
Default
true
Designer category
Appearance

Tasks

public IList<ProjectTask> Tasks

Gets or sets the tasks of the plan, as a flat list with parent references.

Value
The tasks. Never null: the chart starts with an empty ObservableCollection, and setting null gives a new empty one.
Remarks

An ObservableCollection or a BindingList is watched, and so is every task in it, so changes are drawn as they happen. A plain list is read when it is assigned; call Reschedule after changing one.

Every task that is work, not a summary, has a box. Setting a new list scrolls back to the start of the network.

Today

public DateTime? Today

Gets or sets the date the charts treat as today.

Value
A date; only its date part is kept. The default is null, the computer's date.
Default
null
Designer category
Plan
Remarks

The Gantt chart draws its today line from this. A network has no time axis to draw a line on, so the PERT chart draws nothing from it, and changing it does not redraw the chart; it is here so that one set of plan settings can be given to all three charts alike.

WorkingWeek

public WorkingWeek WorkingWeek

Gets or sets the days of the week that are worked. Durations and lags count only these days.

Value
A combination of WorkingWeek flags. The default is WorkingWeek.Weekdays, Monday to Friday; WorkingWeek.None is read as every day being worked.
Default
WorkingWeek.Weekdays
Designer category
Plan

ZoomFactor

public double ZoomFactor

Gets or sets how large the network is drawn, as a multiple of its natural size.

Value
From 0.25 to 3; the default is 1. A value outside that range is brought to the nearer end of it, and NaN or infinity is read as 1.
Default
1.0
Designer category
Layout
Remarks

Setting it keeps the part of the network in the middle of the view where it is, and raises ZoomFactorChanged. ZoomToFit picks the factor that shows the whole network.

Methods

CreateAccessibilityInstance

protected override AccessibleObject CreateAccessibilityInstance()

Creates the accessible object that presents the chart to screen readers and other assistive technology as a list: one item per box, saying the task's dates and float and what it follows and leads to.

Returns

The chart's accessible object.

Dispose

protected override void Dispose(bool disposing)

Stops watching the plan and releases the fonts and the tooltip the chart created.

Parameters
disposing
true when called from Dispose; false from the finaliser.
Remarks

The application's tasks, links and holidays are not touched: they can be given to another chart.

EnsureSchedule

public ProjectSchedule Schedule

Gets the plan as the chart has scheduled it: every task's dates and float, the links that were honoured, the critical path, and anything in the plan that could not be used.

Value
Never null.
Remarks

Scheduled again first when anything has changed, so reading it straight after a change gives the new dates. The schedule returned is a snapshot; read the property again after a change.

ExportImage

public Bitmap ExportImage()

Draws the whole network into a new image, at its natural size: 96 DPI and a ZoomFactor of 1, whatever the screen is showing.

Returns

A 24-bit image at 96 DPI, with a margin of 24 pixels around the network. The caller owns it and must dispose it.

Remarks

The selection and focus are not drawn: the image is a record of the plan, not of the screen. An empty plan gives a small image holding the chart's empty-plan message.

A very large network makes a very large image, and GDI+ refuses a bitmap much beyond a few hundred million pixels with an ArgumentException; for such a network, report from Schedule instead.

Example
using (Bitmap image = network.ExportImage())
{
    Clipboard.SetImage(image);
}

IsInputKey

protected override bool IsInputKey(Keys keyData)

Claims the keys the chart uses for itself, so that the form does not take them for moving the focus or pressing a button.

Parameters
keyData
The key, with its modifiers.
Returns

true for the arrows, Home, End, Page Up and Page Down, and for Enter while a box is selected – so that a dialog's default button keeps Enter otherwise. Otherwise what the base class answers.

OnDpiChangedAfterParent

protected override void OnDpiChangedAfterParent(EventArgs e)

Rebuilds everything measured in device pixels when the chart moves to a display with a different scale: the fonts, the scroll bars and the scroll range.

Parameters
e
Empty event data.

OnFontChanged

protected override void OnFontChanged(EventArgs e)

Raises Control.FontChanged and rebuilds the fonts the boxes are written in.

Parameters
e
Empty event data.

OnGotFocus

protected override void OnGotFocus(EventArgs e)

Draws the focus cue and announces the selected box to screen readers.

Parameters
e
Empty event data.

OnHandleCreated

protected override void OnHandleCreated(EventArgs e)

Fits the scroll bars once the window exists and the display's scale is known for certain, and schedules any changes made before then.

Parameters
e
Empty event data.

OnHandleDestroyed

protected override void OnHandleDestroyed(EventArgs e)

Forgets a refresh posted to a window that is going away; the next window posts again.

Parameters
e
Empty event data.

OnKeyDown

protected override void OnKeyDown(KeyEventArgs e)

Raises Control.KeyDown, then, unless a handler has handled the key, carries out the chart's keyboard commands: the arrows move the selection along the work (Right to what follows, Left to what came before, Up and Down along a column), Home and End go to the first and last box, Page Up and Page Down scroll, Enter raises TaskActivated, and Ctrl with Plus, Minus or 0 zooms in, out, or back to full size.

Parameters
e
The key and its modifiers. Set as handled when the chart acts on it.

OnLostFocus

protected override void OnLostFocus(EventArgs e)

Removes the focus cue.

Parameters
e
Empty event data.

OnMouseCaptureChanged

protected override void OnMouseCaptureChanged(EventArgs e)

Ends a pan when the mouse is taken away part way through, by a message box or a switch of window.

Parameters
e
Empty event data.

OnMouseDoubleClick

protected override void OnMouseDoubleClick(MouseEventArgs e)

Raises Control.MouseDoubleClick, then raises TaskActivated when the double-click was on a box.

Parameters
e
The button, position and click count.

OnMouseDown

protected override void OnMouseDown(MouseEventArgs e)

Raises Control.MouseDown, takes the focus, and with the left button selects the box under the pointer, or starts panning when the press is on the background.

Parameters
e
The button, position and click count.

OnMouseLeave

protected override void OnMouseLeave(EventArgs e)

Raises Control.MouseLeave and hides the tooltip.

Parameters
e
Empty event data.

OnMouseMove

protected override void OnMouseMove(MouseEventArgs e)

Raises Control.MouseMove, then pans while the background is dragged; otherwise shows the tooltip and the hand pointer over a box.

Parameters
e
The button, position and click count.

OnMouseUp

protected override void OnMouseUp(MouseEventArgs e)

Raises Control.MouseUp and ends a pan.

Parameters
e
The button, position and click count.

OnMouseWheel

protected override void OnMouseWheel(MouseEventArgs e)

Raises Control.MouseWheel, then scrolls the network up and down; with Shift, sideways; with Ctrl, zooms about the point under the pointer.

Parameters
e
The wheel's movement and the pointer's position.

OnPaint

protected override void OnPaint(PaintEventArgs e)

Raises Control.Paint, then draws the arrows, the boxes and the focus cue. A fault while drawing is absorbed rather than leaving the control crossed out, and the next paint tries again.

Parameters
e
The graphics to draw with and the area to draw.

OnResize

protected override void OnResize(EventArgs e)

Raises Control.Resize and fits the scroll bars and the view to the new size.

Parameters
e
Empty event data.

OnRightToLeftChanged

protected override void OnRightToLeftChanged(EventArgs e)

Raises Control.RightToLeftChanged and lays the network out again mirrored, so the work runs from right to left, scrolled to its start.

Parameters
e
Empty event data.

OnScheduleChanged

protected virtual void OnScheduleChanged(EventArgs e)

Raises the ScheduleChanged event.

Parameters
e
Empty event data.
Remarks

A derived chart that overrides this should call the base method, or the event is not raised.

OnSelectedTaskChanged

protected virtual void OnSelectedTaskChanged(EventArgs e)

Raises the SelectedTaskChanged event.

Parameters
e
Empty event data.
Remarks

A derived chart that overrides this should call the base method, or the event is not raised.

OnTaskActivated

protected virtual void OnTaskActivated(TaskEventArgs e)

Raises the TaskActivated event.

Parameters
e
The task that was activated.
Remarks

A derived chart that overrides this should call the base method, or the event is not raised.

OnZoomFactorChanged

protected virtual void OnZoomFactorChanged(EventArgs e)

Raises the ZoomFactorChanged event.

Parameters
e
Empty event data.
Remarks

A derived chart that overrides this should call the base method, or the event is not raised.

Reschedule

public void Reschedule()

Schedules the plan and lays the network out again now, and raises ScheduleChanged.

Remarks

Needed only after changing a plain list given to Tasks, Links or Holidays, which the chart cannot watch.

ScrollToTask

public void ScrollToTask(ProjectTask task)

Scrolls the chart until a task's box is in view, with a little space around it.

Parameters
task
The task to show. Nothing happens for null or a task that has no box.
Remarks

The selection is left as it is; set SelectedTask to select the task as well, which scrolls to it too.

ZoomToFit

public void ZoomToFit()

Sets ZoomFactor so that the whole network fits the control, and scrolls to its start.

Remarks

The factor is rounded down to a twentieth, so the network has a little room to spare, and is never below 0.25: a network too large to fit at that size still scrolls. Call it once the chart has its final size, from the form's Shown event, say. Does nothing for an empty plan.

Events

ScheduleChanged

public event EventHandler ScheduleChanged

Occurs after the plan has been scheduled again because something changed: a task, a link, a collection, a calendar setting, or a call to Reschedule.

Designer category
Behavior
Remarks

Raised from the message loop, once for any number of changes made together, and never from inside a paint, so a handler is free to change the plan again. Not raised for the chart's first schedule.

SelectedTaskChanged

public event EventHandler SelectedTaskChanged

Occurs when the selected box changes: by the reader, by setting SelectedTask, or because the selected task left the plan.

Designer category
Behavior

TaskActivated

public event EventHandler<TaskEventArgs> TaskActivated

Occurs when the reader double-clicks a box or presses Enter with a box selected: the moment to open the application's own view of the task.

Designer category
Action

ZoomFactorChanged

public event EventHandler ZoomFactorChanged

Occurs when ZoomFactor changes, by the property, ZoomToFit, Ctrl and the wheel, or Ctrl and Plus, Minus or 0.

Designer category
Property Changed