All docs
V20.1
20.2 (EAP/Beta)
20.1
19.2
The page you are viewing does not exist in version 19.2. This link will take you to the root page.
19.1
The page you are viewing does not exist in version 19.1. This link will take you to the root page.
18.2
The page you are viewing does not exist in version 18.2. This link will take you to the root page.
18.1
The page you are viewing does not exist in version 18.1. This link will take you to the root page.
17.2
The page you are viewing does not exist in version 17.2. This link will take you to the root page.

Get Started

  • 15 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.

In the control's smart 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 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.

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.

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.

    TIP

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

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

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

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.

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.

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:

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.

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 Interactive Editing and Automatic Scheduling for more information.

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.

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 Edit Form for more information.

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.

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.

See Workweek Schedule and Exceptions for more information.

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.

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 Tasks, Summaries, and Milestones for more information and code samples.