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.
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 | |
|---|---|
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 | Gets or sets the fill of a box. |
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. |
ColumnGap | Gets or sets the space between one column of boxes and the next, where the arrows run. |
ConnectorColor | Gets or sets the colour of the arrows between boxes that are not critical. |
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. |
Holidays | Gets or sets the dates that are not worked, such as public holidays. |
Links | Gets or sets the dependencies between the tasks: the arrows between the boxes. |
NodeHeight | Gets or sets the height of a box. |
NodeWidth | Gets or sets the width of a box. |
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. |
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. |
RowGap | Gets or sets the space between one row of boxes and the next, where arrows that pass several columns run. |
SelectedTask | Gets or sets the task whose box is selected. |
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. |
Tasks | Gets or sets the tasks of the plan, as a flat list with parent references. |
Today | Gets or sets the date the charts treat as today. |
WorkingWeek | Gets or sets the days of the week that are worked. Durations and lags count only these days. |
ZoomFactor | Gets or sets how large the network is drawn, as a multiple of its natural size. |
| Methods | |
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. |
Dispose | Stops watching the plan and releases the fonts and the tooltip the chart created. |
EnsureSchedule | 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. |
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. |
IsInputKey | Claims the keys the chart uses for itself, so that the form does not take them for moving the focus or pressing a button. |
OnDpiChangedAfterParent | 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. |
OnFontChanged | Raises Control.FontChanged and rebuilds the fonts the boxes are written in. |
OnGotFocus | Draws the focus cue and announces the selected box to screen readers. |
OnHandleCreated | Fits the scroll bars once the window exists and the display's scale is known for certain, and schedules any changes made before then. |
OnHandleDestroyed | Forgets a refresh posted to a window that is going away; the next window posts again. |
OnKeyDown | 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. |
OnLostFocus | Removes the focus cue. |
OnMouseCaptureChanged | Ends a pan when the mouse is taken away part way through, by a message box or a switch of window. |
OnMouseDoubleClick | Raises Control.MouseDoubleClick, then raises TaskActivated when the
double-click was on a box. |
OnMouseDown | 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. |
OnMouseLeave | Raises Control.MouseLeave and hides the tooltip. |
OnMouseMove | Raises Control.MouseMove, then pans while the background is dragged; otherwise shows
the tooltip and the hand pointer over a box. |
OnMouseUp | Raises Control.MouseUp and ends a pan. |
OnMouseWheel | Raises Control.MouseWheel, then scrolls the network up and down; with Shift,
sideways; with Ctrl, zooms about the point under the pointer. |
OnPaint | 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. |
OnResize | Raises Control.Resize and fits the scroll bars and the view to the new size. |
OnRightToLeftChanged | Raises Control.RightToLeftChanged and lays the network out again mirrored, so the
work runs from right to left, scrolled to its start. |
OnScheduleChanged | Raises the ScheduleChanged event. |
OnSelectedTaskChanged | Raises the SelectedTaskChanged event. |
OnTaskActivated | Raises the TaskActivated event. |
OnZoomFactorChanged | Raises the ZoomFactorChanged event. |
Reschedule | Schedules the plan and lays the network out again now, and raises ScheduleChanged. |
ScrollToTask | Scrolls the chart until a task's box is in view, with a little space around it. |
ZoomToFit | Sets ZoomFactor so that the whole network fits the control, and scrolls to its start. |
| Events | |
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. |
SelectedTaskChanged | Occurs when the selected box changes: by the reader, by setting SelectedTask, or
because the selected task left the plan. |
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. |
ZoomFactorChanged | Occurs when ZoomFactor changes, by the property, ZoomToFit, Ctrl and
the wheel, or Ctrl and Plus, Minus or 0. |
Constructors
PertChart
Properties
BoxBackColor
Gets or sets the fill of a box.
- Value
- The default is
Color.Empty, a fill a shade away fromControl.BackColortowardsControl.ForeColor. - Designer category
- Appearance
Remarks
In Windows high-contrast mode the system colours are used instead.
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 betweenControl.BackColorandControl.ForeColor. - Designer category
- Appearance
Remarks
In Windows high-contrast mode the system colours are used instead.
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
Gets or sets the colour of the arrows between boxes that are not critical.
- Value
- The default is
Color.Empty, a shade betweenControl.BackColorandControl.ForeColor. - Designer category
- Appearance
Remarks
In Windows high-contrast mode the system colours are used instead.
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
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 emptyObservableCollection, and settingnullgives a new empty one.
Remarks
Durations and lags skip these dates. An observable collection is watched; after changing a
plain list, call Reschedule.
Links
Gets or sets the dependencies between the tasks: the arrows between the boxes.
- Value
- The links. Never
null: the chart starts with an emptyObservableCollection, and settingnullgives a new empty one.
Remarks
Watched in the same way as Tasks. The chart never changes the list.
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
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
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
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 plannedProjectTask.Startin the plan, then the earliest plannedProjectTask.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
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
Gets or sets the task whose box is selected.
- Value
- A task in
Tasks, ornull(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
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
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 emptyObservableCollection, and settingnullgives 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
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
Gets or sets the days of the week that are worked. Durations and lags count only these days.
- Value
- A combination of
WorkingWeekflags. The default isWorkingWeek.Weekdays, Monday to Friday;WorkingWeek.Noneis read as every day being worked. - Default
WorkingWeek.Weekdays- Designer category
- Plan
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
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
Stops watching the plan and releases the fonts and the tooltip the chart created.
Parameters
disposingtruewhen called fromDispose;falsefrom the finaliser.
Remarks
The application's tasks, links and holidays are not touched: they can be given to another chart.
EnsureSchedule
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
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
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
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
Raises Control.FontChanged and rebuilds the fonts the boxes are written in.
Parameters
e- Empty event data.
OnGotFocus
Draws the focus cue and announces the selected box to screen readers.
Parameters
e- Empty event data.
OnHandleCreated
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
Forgets a refresh posted to a window that is going away; the next window posts again.
Parameters
e- Empty event data.
OnKeyDown
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
Removes the focus cue.
Parameters
e- Empty event data.
OnMouseCaptureChanged
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
Raises Control.MouseDoubleClick, then raises TaskActivated when the
double-click was on a box.
Parameters
e- The button, position and click count.
OnMouseDown
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
Raises Control.MouseLeave and hides the tooltip.
Parameters
e- Empty event data.
OnMouseMove
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
Raises Control.MouseUp and ends a pan.
Parameters
e- The button, position and click count.
OnMouseWheel
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
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
Raises Control.Resize and fits the scroll bars and the view to the new size.
Parameters
e- Empty event data.
OnRightToLeftChanged
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
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
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
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
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
Schedules the plan and lays the network out again now, and raises ScheduleChanged.
Remarks
ScrollToTask
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
nullor 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
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
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
Occurs when the selected box changes: by the reader, by setting SelectedTask, or
because the selected task left the plan.
- Designer category
- Behavior
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
Occurs when ZoomFactor changes, by the property, ZoomToFit, Ctrl and
the wheel, or Ctrl and Plus, Minus or 0.
- Designer category
- Property Changed