HypernovaDesktop Components · docs
Binarymission
WPF › Project Management

Project Management

.NET Framework 4.8.NET 6 / 8 / 10v1.0.0WPF

A Gantt chart: the plan as a task list beside a timeline of bars, with the links between the tasks, the milestones, the baselines and the critical path, scheduled on a working calendar and editable with the mouse or the keyboard alone.

25public types
431public members
1namespaces

Assembly

AssemblyBinarymission.WPF.Controls.ProjectManagement.dll
Root namespaceBinarymission.WPF.Controls.ProjectManagement
Target frameworks.NET Framework 4.8, .NET 6 / 8 / 10

Overview

Use it wherever work is planned against dates – a product launch, a fit-out, a release – to answer what a planner asks of a plan (when does it finish, what is late, which tasks have no slack) and to let them change it by dragging.

The plan

A plan is two lists that belong to the application: Tasks, a flat list of ProjectTask objects in which a subtask names its summary through ProjectTask.ParentId, and Links, the TaskLink dependencies between them – the shape a database table or a spreadsheet already has. An ObservableCollection is watched, and so is every task and link in it: change a property and the chart schedules again and redraws.

Scheduling

Dates are worked out by the critical-path method on working days – the days WorkingWeek names, less the Holidays, from ProjectStart. A task starts on its planned ProjectTask.Start or as soon as its links allow, whichever is later, and a summary spans its subtasks. The result is in Schedule, and ScheduleChanged says when it has been worked out again. Bad data never stops the chart: a link to a missing task, or a loop, is left out and reported in ProjectSchedule.Problems, and everything else is drawn.

The two panes

The task list on the left shows the outline and the Columns you choose; the timeline on the right shows a bar for each task, a diamond for each milestone and a bracket for each summary, at the scale Zoom sets. The panes scroll up and down together; the splitter between them sets GridWidth.

Editing

Drag a bar to move the task, its right-hand end to change its length, or the triangle under it to set its progress; drag from the dot past its end to another row to link the two finish-to-start. Press F2 to type into the current cell – name, start, days, % done or predecessors (outline numbers such as 2, 3SS+1). Every edit is offered first through TaskChanging or LinksChanging, which can cancel it, then made to the task or link object itself and announced by TaskChanged or LinksChanged. IsReadOnly allows looking only.

The keyboard

KeysWhat they do

Up, Down, Home, End, Page Up, Page Down

Move between rows.

Right, Left

Open or close a summary, or go to its first subtask or back; in other columns, move between cells.

F2; Enter or Space

Edit the current cell; raise TaskActivated.

Shift+Left, Shift+Right

Move the task a working day earlier or later.

Ctrl+Shift+Left, Ctrl+Shift+Right

Make it a working day shorter or longer.

Ctrl+Plus, Ctrl+Minus, Ctrl+0

Zoom in, out, or to fit the plan. Esc cancels a drag.

One plan, three views

Give the same lists to a PertChart and a TaskBoard and the three agree: they schedule the same objects with the same arithmetic, so a bar dragged here or a card moved on the board is seen by all of them.

Appearance

The chart draws itself and has no template. Control.Background, Control.Foreground and the font apply as usual; the bars, links and calendar have brush properties (BarBrush, CriticalBrush and the rest) whose defaults read on light and dark backgrounds alike, and in Windows high contrast the system colours replace them all. The chart always runs left to right, as a calendar does. ExportImage and Print draw the whole plan.

Getting started

A window that plans a website relaunch, built in code so that it stands on its own; in XAML the lists are bound, as in <pm:GanttChart Tasks="{Binding Tasks}" Links="{Binding Links}" Zoom="Week" /> with xmlns:pm="clr-namespace:Binarymission.WPF.Controls.ProjectManagement;assembly=Binarymission.WPF.Controls.ProjectManagement".

using System;
using System.Collections.ObjectModel;
using System.Windows;
using Binarymission.WPF.Controls.ProjectManagement;

public sealed class PlanWindow : Window
{
    public PlanWindow()
    {
        var tasks = new ObservableCollection<ProjectTask>
        {
            new ProjectTask("design", "Design"),                     // a summary: it has subtasks
            new ProjectTask("wire", "Wireframes", 5)    { ParentId = "design", Assignee = "Priya Shah", Progress = 100 },
            new ProjectTask("look", "Visual design", 8) { ParentId = "design", Assignee = "Tom Ellis", Progress = 40 },
            new ProjectTask("build", "Build"),
            new ProjectTask("web", "Front end", 10)     { ParentId = "build", Assignee = "Ana Ruiz" },
            new ProjectTask("api", "Orders API", 12)    { ParentId = "build", Assignee = "Sam Okafor" },
            new ProjectTask("live", "Go live", 0),                    // no length: a milestone
        };
        var links = new ObservableCollection<TaskLink>
        {
            new TaskLink("wire", "look"),                             // finish-to-start
            new TaskLink("look", "web", TaskLinkType.StartToStart, 3), // 3 working days after it starts
            new TaskLink("wire", "api"),
            new TaskLink("web", "live"),
            new TaskLink("api", "live"),
        };

        var gantt = new GanttChart
        {
            Tasks = tasks,
            Links = links,
            ProjectStart = new DateTime(2026, 11, 2),
            Columns = GanttColumns.Default | GanttColumns.Assignee,
        };
        gantt.Holidays.Add(new DateTime(2026, 12, 25));

        // A finished task stays where it is, whichever way the reader tries to move it.
        gantt.TaskChanging += (sender, e) =>
            e.Cancel = e.Task.Progress >= 100 && (e.NewStart.HasValue || e.NewDuration.HasValue);
        gantt.ScheduleChanged += (sender, e) =>
            Title = "Website relaunch - finishes " + gantt.Schedule.ProjectFinish.ToString("d MMM yyyy");

        Content = gantt;
        Loaded += (sender, e) => gantt.ZoomToFit();
    }
}

API reference

Binarymission.WPF.Controls.ProjectManagement

class BoardColumnA column of the task board: one value of Status, the heading shown for it, and the most cards it should hold.
enum BoardLaneByWhat 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 CardMovingEventArgsProvides 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 GanttChartA Gantt chart: the plan as a task list beside a timeline of bars, with the links between the tasks, the milestones, the baselines and the critical path, scheduled on a working calendar and editable with the mouse or the keyboard alone.
enum GanttColumnsThe columns of the Gantt chart's task list, as flags that combine. The task's name is always shown.
enum GanttZoomHow much time the Gantt chart's timeline shows, from a column per day to a column per half-year.
class LinksChangingEventArgsProvides 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 PertChartA PERT chart: the plan as a network of boxes, one for each piece of work, joined by arrows in the order the work has to happen, each box showing the dates and float the critical-path method gives its task.
class ProjectScheduleA 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 ProjectSchedulerSchedules 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 ProjectTaskOne 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 ScheduleInputEverything Schedule(ScheduleInput) needs to schedule a plan: the tasks, the links between them, the project's first day and the working calendar.
class ScheduleProblemSomething 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 ScheduleProblemKindWhat 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 ScheduledLinkOne link as the scheduler used it. Links that could not be honoured are not here; they are in Problems instead.
class ScheduledTaskOne 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 TaskBoardA task board: the plan as cards in columns - one column for each stage of the work, one card for each task - with optional lanes across the board by assignee, category or phase, and cards that move with the mouse or the keyboard.
class TaskChangingEventArgsProvides 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 TaskConstraintKindHow 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 TaskEditSourceHow a change to the plan was made: with the pointer, the keyboard, by typing in a cell, or by the application.
class TaskEventArgsProvides data for the events that concern one task: a task changed, activated, opened or closed, or a card moved.
class TaskLinkA dependency between two tasks: the successor (ToId) waits for the predecessor (FromId) in the way Type says, give or take Lag working days.
enum TaskLinkTypeWhich 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 WorkCalendarA 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 WorkingWeekThe 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.