Skip to main content
A newer version of this page is available. .

Get Started

  • 16 minutes to read

This tutorial shows how to use the GanttControl — how to populate it with data, specify the workweek schedule, allow users to modify tasks in the chart, enable a modal form to edit tasks in the task list, and how to customize task appearance.

Add the Control to a Form

Create a new project in Visual Studio. Drop the GanttControl from the Toolbox window onto the main application form.

new gantt project

In the control’s smart gantt smart tag tag menu, click Create Ribbon and Dock in Parent Container to add the ribbon with chart commands to the form and make the Gantt control fill all the available space.

Populate the Control with Data

You can bind the control to a data source in code or in the designer. Use the following properties to assign a data source to the control:

The GanttControl supports the same binding modes as the TreeList. See Data Binding for details on how to bind the TreeList to a data source. For more information about mapping to data source fields in the GanttControl, see the Bind to Data Source topic. For general information about binding DevExpress controls to data sources, see Data Binding Common Concepts.

This tutorial shows how to bind the control to a sample business object and data exported from Microsoft Project.

Note

Make sure that you specified all required mappings. Otherwise, specific functionality may not be available. See the following topic for more information: Bind to Data Source.

Important

If you use all three time-related task properties (StartDateFieldName, FinishDateFieldName, Duration), make sure the Duration does not conflict with Start and Finish dates. Since the control draws tasks depending on Start and Finish dates, these conflicts can be masked until you try to edit a task. For example:

  • StartDate — February 10, 2021, 1:00 p.m.
  • FinishDate — February 11, 2021, 1:00 p.m.
  • Duration — 24 hours (1 day)
  • ScheduleMode — Auto
  • Work day duration — 8 hours

This setup introduces a conflict: the 24-hour task duration means a task should span across three days (eight working hours a day), which mismatches StartDate-FinishDate values. The control will draw a 24-hour task based on Start and Finish dates, but the 3-day duration will be stored internally, and will cause issues when a task is edited.

Business Objects

You can use business objects to store data. The example below creates a collection of Task objects and assigns it to the DataSource property. The data source also contains information about finish-to-start dependencies between tasks.

The resulting application window is shown in the figure below.

sample gantt data

using System;
using System.ComponentModel;
using System.Collections.Generic;

ganttControl1.TreeListMappings.KeyFieldName = "Id";
ganttControl1.TreeListMappings.ParentFieldName = "ParentId";
ganttControl1.ChartMappings.TextFieldName = "Name";
ganttControl1.ChartMappings.StartDateFieldName = "StartDate";
ganttControl1.ChartMappings.FinishDateFieldName = "FinishDate";
ganttControl1.ChartMappings.DurationFieldName = "Duration";
ganttControl1.ChartMappings.PredecessorsFieldName = "Predecessors";
ganttControl1.ChartMappings.ProgressFieldName = "Progress";
ganttControl1.DataSource = LoadData();

public static IList<Task> LoadData() {
    var tasks = new List<Task>();
    Task softwareDevelopment = new Task("Software Development", 0, -1, DateTime.Now, 1, 24);
    Task analyseRequirements = new Task("Analyse Requirements", 1, softwareDevelopment.Id, softwareDevelopment.StartDate, 1, 100);
    Task developFunctionalSpecifications = new Task("Develop functional specifications", 2, softwareDevelopment.Id, analyseRequirements.FinishDate, 1, 100, 1);
    Task developSoftware = new Task("Develop software", 3, softwareDevelopment.Id, developFunctionalSpecifications.FinishDate, 5, 40, developFunctionalSpecifications.Id);
    Task developHelpSystem = new Task("Develop help system", 4, softwareDevelopment.Id, developFunctionalSpecifications.FinishDate, 1, 90, developFunctionalSpecifications.Id);
    Task developUserManuals = new Task("Develop user manuals", 5, softwareDevelopment.Id, developHelpSystem.FinishDate, 1, 0, developHelpSystem.Id);
    Task testSoftware = new Task("Test software", 6, softwareDevelopment.Id, developSoftware.FinishDate, 2, 0, developSoftware.Id);
    Task deployBeta = new Task("Deploy Beta", 7, softwareDevelopment.Id, testSoftware.FinishDate, 0, 0, testSoftware.Id);
    Task collectFeedback = new Task("Collect feedback", 8, softwareDevelopment.Id, deployBeta.FinishDate, 2, 0, deployBeta.Id);
    Task fixBugs = new Task("Fix bugs", 9, softwareDevelopment.Id, collectFeedback.FinishDate, 2, 0, collectFeedback.Id);
    Task incorporateFeedBack = new Task("Incorporate feedback", 10, softwareDevelopment.Id, collectFeedback.FinishDate, 3, 0, collectFeedback.Id);
    Task releaseSoftware = new Task("Release software", 11, softwareDevelopment.Id, incorporateFeedBack.FinishDate, 2, 0, fixBugs.Id, incorporateFeedBack.Id);
    Task createSoftwareMaintenanceTeam = new Task("Create software maintenance team", 12, softwareDevelopment.Id, deployBeta.FinishDate, 1, 0, developSoftware.Id);
    Task softwareDevelopmentComplete = new Task("Software development complete", 13, softwareDevelopment.Id, releaseSoftware.FinishDate, 0, 0, releaseSoftware.Id);
    softwareDevelopment.FinishDate = softwareDevelopmentComplete.FinishDate;
    tasks.AddRange(new Task[] {softwareDevelopment, analyseRequirements, developFunctionalSpecifications, developSoftware, developHelpSystem, developUserManuals,
        testSoftware,deployBeta,collectFeedback, fixBugs, incorporateFeedBack, releaseSoftware, createSoftwareMaintenanceTeam, softwareDevelopmentComplete });
    return tasks;
}

public class Task{
    public Task(string name, int id, int parentId, DateTime start, int duration, double progress, params int[] predecessors) {
        Name = name;
        Id = id;
        ParentId = parentId;
        StartDate = start;
        Duration = TimeSpan.FromDays(duration);
        FinishDate = start + Duration;
        Progress = progress;
        Predecessors = new BindingList<int>();
        foreach (int predecessor in predecessors) {
           Predecessors.Add(predecessor);
        }
    }
    public int Id { get; set; }
    public int ParentId { get; set; }
    public BindingList<int> Predecessors { get; private set; }
    public string Name { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime FinishDate { get; set; }
    public TimeSpan Duration { get; set; }
    public double Progress { get; set; }
}

Data from Microsoft Project

To use data from Microsoft Project, export data to a file and then convert the data to an appropriate format. In this example, data is stored in a DataTable. To store dependencies, this example uses a separate data source assigned to the DependencySource property.

Export Data from Microsoft Project

  1. Save a project as a tab-delimited text file.

    gantt data export

    Tip

    You may need to enable legacy formats in the Trust Center window to enable export to text files. To open this window, click File - Options - Trust Center - Trust Center Settings…

  2. Select tasks. Do not include headers. Click Next.

    wizard options

  3. Select data fields to export in the following order: ID, WBS (work breakdown structure), Name, Start, Finish, Predecessors, Resource Names. Click Finish.

    wizard task mapping

This tutorial uses the Software Development Plan template from Microsoft Project. The first three lines contain the following data:

0   0   Software Development    4/21/20 8:00 AM 9/1/20 3:00 PM      
1   1   Scope   4/21/20 8:00 AM 4/24/20 12:00 PM        
2   1.1 Determine project scope 4/21/20 8:00 AM 4/21/20 12:00 PM        Management

Import Data to a Table in Code

Use the following code to create tables that contain data from the file. The resulting application window is shown in the figure below.

import data

using DevExpress.XtraGantt;
using System;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;

// Specify data fields that contain
// information about tasks required for
// the control to display the project.
ganttControl1.TreeListMappings.KeyFieldName = "ID";
ganttControl1.TreeListMappings.ParentFieldName = "ParentID";
ganttControl1.ChartMappings.StartDateFieldName = "StartDate";
ganttControl1.ChartMappings.FinishDateFieldName = "FinishDate";
ganttControl1.ChartMappings.TextFieldName = "Resources";

// Specify data fields that contain
// information about dependencies between tasks.
ganttControl1.DependencyMappings.PredecessorFieldName = "PredecessorID";
ganttControl1.DependencyMappings.SuccessorFieldName = "SuccessorID";
ganttControl1.DependencyMappings.TypeFieldName = "Type";

// Specify the path to the exported project.
string path = "c:\\export\\project1.txt";
DataTable tasks = new DataTable();
DataTable dependencies = new DataTable();
PopulateDataSources(path, ref tasks, ref dependencies);
ganttControl1.DataSource = tasks;
ganttControl1.DependencySource = dependencies;


public static void PopulateDataSources(string path, ref DataTable tasks, ref DataTable dependencies) {
    // Create columns for the table that contains tasks.
    DataColumn colId = new DataColumn("ID", typeof(string));
    DataColumn colParentId = new DataColumn("ParentID", typeof(string));
    DataColumn colText = new DataColumn("Text", typeof(string));
    DataColumn colStart = new DataColumn("StartDate", typeof(DateTime));
    DataColumn colFinish = new DataColumn("FinishDate", typeof(DateTime));
    DataColumn colDuration = new DataColumn("Duration", typeof(TimeSpan));
    DataColumn colResources = new DataColumn("Resources", typeof(string));
    DataColumn colWbs = new DataColumn("WBS", typeof(string));
    tasks.Columns.AddRange(new DataColumn[] { colId, colParentId, colText, colStart, colFinish, colDuration, colResources, colWbs });
    // Create columns for the table that contains dependencies.
    DataColumn colPredecessor = new DataColumn("PredecessorID", typeof(string));
    DataColumn colSuccessor = new DataColumn("SuccessorID", typeof(string));
    DataColumn colType = new DataColumn("Type", typeof(DevExpress.XtraGantt.DependencyType));
    dependencies.Columns.AddRange(new DataColumn[] { colPredecessor, colSuccessor, colType });
    // Read from the file.
    using (StreamReader sr = new StreamReader(path)) {
        while (sr.Peek() >= 0) {
            string line = sr.ReadLine();
            string[] values = line.Split('\t');
            string taskId = values[0];
            // Get parent ID for each task
            // from the work breakdown structure
            // used in MS Project.
            string taskParentId = string.Empty;
            string[] pathWbs = values[1].Split('.');
            if (pathWbs.Length == 1)
                taskParentId = "0";
            else {
                string parentWbs = string.Join(".", pathWbs.Take(pathWbs.Length - 1));
                foreach (DataRow row in tasks.Rows) {
                    string rowWbs = (string)row[colWbs];
                    if (rowWbs == parentWbs) {
                        taskParentId = (string)row[colId];
                    }
                }
            }
            // Convert strings to DateTime structures.
            DateTime taskStartDate = DateTime.Parse(values[3], CultureInfo.CurrentCulture);
            DateTime taskFinishDate = DateTime.Parse(values[4], CultureInfo.CurrentCulture);
            // This example calculates the duration
            // instead of importing it from the file.
            TimeSpan taskDuration = taskFinishDate - taskStartDate;
            // Add a new row with the values to the table.
            tasks.Rows.Add(new object[] {
                taskId,
                taskParentId,
                values[2], // Text.
                taskStartDate,
                taskFinishDate,
                taskDuration,
                values[6], // Resource Names.
                values[1] // Work breakdown structure.
            });
            string[] taskPredecessors = taskPredecessors = values[5].Split(',');
            if (taskPredecessors.Length > 0) {
                foreach (string value in taskPredecessors) {
                    DependencyType dependencyType = DependencyType.FinishToStart;
                    string predecessorId = value;
                    if (value.Contains("FS")) {
                        dependencyType = DependencyType.FinishToStart;
                        predecessorId = value.Substring(0, value.IndexOf("FS"));
                        // This example ignores the time lag.
                        string timeLag = value.Substring(value.IndexOf("FS") + 2, value.Length - value.IndexOf("FS") - 2);
                    }
                    if (value.Contains("FF")) {
                        dependencyType = DependencyType.FinishToFinish;
                        predecessorId = value.Substring(0, value.IndexOf("FF"));
                    }
                    if (value.Contains("SS")) {
                        dependencyType = DependencyType.StartToStart;
                        predecessorId = value.Substring(0, value.IndexOf("SS"));
                    }
                    if (value.Contains("SF")) {
                        dependencyType = DependencyType.StartToFinish;
                        predecessorId = value.Substring(0, value.IndexOf("SF"));
                    }
                    dependencies.Rows.Add(new object[] { predecessorId, taskId, dependencyType });
                }
            }
        }
    }
}

Edit Tasks

Users can use cell editors to edit tasks in the task list.

inplace editors

You can enable a modal form instead of cell editors or allow users to edit tasks in the chart.

Edits in Chart

To allow users to modify tasks in the chart, enable the following options:

interactive editing

ganttControl1.OptionsCustomization.AllowModifyTasks = DevExpress.Utils.DefaultBoolean.True;
ganttControl1.OptionsCustomization.AllowModifyProgress = DevExpress.Utils.DefaultBoolean.True;
ganttControl1.OptionsCustomization.AllowModifyDependencies = DevExpress.Utils.DefaultBoolean.True;

Respond to Task Changes

When a user modifies a task, the control raises events. You can handle these events to customize the operation. For example, the TaskMoveCompleted event fires when a user finishes moving a task to a new time slot, and allows you to cancel the operation. The code below shows how to ask for confirmation when a user moves a task beyond the project bounds.

confirmation message

ganttControl1.TaskMoveCompleted += GanttControl1_TaskMoveCompleted;

private void GanttControl1_TaskMoveCompleted(object sender, TaskMovingEventArgs e) {
    if (e.CurrentTaskStart < ganttControl1.Nodes[0].GetStartDate())
        e.Cancel = XtraMessageBox.Show(String.Format("You moved '{0}' to start before the project starts. Do you want to proceed?", e.ProcessedTask.Text), "Planning Wizard", MessageBoxButtons.YesNo) != DialogResult.Yes;
    if (e.CurrentTaskFinish > ganttControl1.Nodes[0].GetFinishDate())
        e.Cancel = XtraMessageBox.Show(String.Format("You moved '{0}' to finish after the project finishes. Do you want to proceed?", e.ProcessedTask.Text), "Planning Wizard", MessageBoxButtons.YesNo) != DialogResult.Yes;
}

See the following topic for more information: Interactive Editing.

Edits in Modal Form

To enable a modal form instead of cell editors, set the EditingMode property to EditForm. You can also customize the form layout or use a custom form.

gantt edit form

ganttControl1.OptionsBehavior.EditingMode = DevExpress.XtraTreeList.TreeListEditingMode.EditForm;
ganttControl1.OptionsEditForm.FormCaptionFormat = "Summary Task Information - {Text}";
ganttControl1.Columns["StartDate"].OptionsEditForm.StartNewRow = true;
ganttControl1.Columns["Text"].OptionsEditForm.VisibleIndex = -2;
ganttControl1.Columns["Duration"].OptionsEditForm.VisibleIndex = -1;
ganttControl1.Columns["Text"].OptionsEditForm.UseEditorColRowSpan = false;
ganttControl1.Columns["Text"].OptionsEditForm.ColumnSpan = 2;
ganttControl1.Columns["Resources"].OptionsEditForm.UseEditorColRowSpan = false;
ganttControl1.Columns["Resources"].OptionsEditForm.ColumnSpan = 3;
ganttControl1.Columns["Resources"].OptionsEditForm.StartNewRow = true;

See the following topic for more information: Edit Form.

Automatic Scheduling

If the ScheduleMode property is set to Auto, the control automatically reschedules successor tasks when a user modifies a particular task. Set this property to Manual to disable automatic scheduling.

automatic scheduling

ganttControl1.OptionsBehavior.ScheduleMode = DevExpress.XtraGantt.Options.ScheduleMode.Auto;

Workweek Schedule and Holidays

The control takes the workweek schedule and holidays into account when it reschedules tasks. To specify the workweek schedule and holidays, click Run Designer in the control’s smart tag menu and switch to the Work Week Schedule section.

work week schedule

See the following topic for more information: Workweek Schedule and Exceptions.

Customize Task Appearance

The control gives you access to the drawing surface when a task is about to be drawn on-screen. You can draw a task or customize appearance settings. The code below shows how to customize the background color of tasks that missed a deadline.

deadline

DateTime deadLine = new DateTime(2020, 8, 26);
private void GanttControl1_CustomDrawTask(object sender, CustomDrawTaskEventArgs e) {
    if (e.FinishDate > deadLine)
        e.Info.Appearance.BackColor = Color.Red;
}

See the following topic for more information and code samples: Tasks, Summaries, and Milestones.