Back to Devexpress

Get Started

windowsforms-401744-controls-and-libraries-gantt-control-getting-started.md

latest33.8 KB
Original Source

Get Started

  • Aug 19, 2021
  • 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.

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:

  • DataSource — specifies the data source that contains tasks. The TreeListMappings and ChartMappings specify data source fields that contain the following data:

  • DependencySource — specifies the data source that contains dependencies. This data source allows you to support all dependency types. The DependencyMappings specify data source fields that contain the following data:

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.

csharp
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; }
}
vb
Imports System
Imports System.ComponentModel
Imports 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 Shared Function LoadData() As IList(Of Task)
    Dim tasks = New List(Of Task)()
    Dim softwareDevelopment As New Task("Software Development", 0, -1, DateTime.Now, 1, 24)
    Dim analyseRequirements As New Task("Analyse Requirements", 1, softwareDevelopment.Id, softwareDevelopment.StartDate, 1, 100)
    Dim developFunctionalSpecifications As New Task("Develop functional specifications", 2, softwareDevelopment.Id, analyseRequirements.FinishDate, 1, 100, 1)
    Dim developSoftware As New Task("Develop software", 3, softwareDevelopment.Id, developFunctionalSpecifications.FinishDate, 5, 40, developFunctionalSpecifications.Id)
    Dim developHelpSystem As New Task("Develop help system", 4, softwareDevelopment.Id, developFunctionalSpecifications.FinishDate, 1, 90, developFunctionalSpecifications.Id)
    Dim developUserManuals As New Task("Develop user manuals", 5, softwareDevelopment.Id, developHelpSystem.FinishDate, 1, 0, developHelpSystem.Id)
    Dim testSoftware As New Task("Test software", 6, softwareDevelopment.Id, developSoftware.FinishDate, 2, 0, developSoftware.Id)
    Dim deployBeta As New Task("Deploy Beta", 7, softwareDevelopment.Id, testSoftware.FinishDate, 0, 0, testSoftware.Id)
    Dim collectFeedback As New Task("Collect feedback", 8, softwareDevelopment.Id, deployBeta.FinishDate, 2, 0, deployBeta.Id)
    Dim fixBugs As New Task("Fix bugs", 9, softwareDevelopment.Id, collectFeedback.FinishDate, 2, 0, collectFeedback.Id)
    Dim incorporateFeedBack As New Task("Incorporate feedback", 10, softwareDevelopment.Id, collectFeedback.FinishDate, 3, 0, collectFeedback.Id)
    Dim releaseSoftware As New Task("Release software", 11, softwareDevelopment.Id, incorporateFeedBack.FinishDate, 2, 0, fixBugs.Id, incorporateFeedBack.Id)
    Dim createSoftwareMaintenanceTeam As New Task("Create software maintenance team", 12, softwareDevelopment.Id, deployBeta.FinishDate, 1, 0, developSoftware.Id)
    Dim softwareDevelopmentComplete As 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
End Function

Public Class Task
    Public Sub New(ByVal taskName As String, ByVal taskId As Integer, ByVal taskParentId As Integer, ByVal start As DateTime,
                   ByVal taskDuration As Integer, ByVal taskProgress As Double, ParamArray ByVal predecessorIds() As Integer)
        Me.Name = taskName
        Me.Id = taskId
        Me.ParentId = taskParentId
        StartDate = start
        Me.Duration = TimeSpan.FromDays(taskDuration)
        FinishDate = start.Add(Me.Duration)
        Me.Progress = taskProgress
        Me.Predecessors = New BindingList(Of Integer)()
        For Each predecessor As Integer In predecessorIds
            Me.Predecessors.Add(predecessor)
        Next predecessor
    End Sub
    Public Property Id() As Integer
    Public Property ParentId() As Integer
    Private privatePredecessors As BindingList(Of Integer)
    Public Property Predecessors() As BindingList(Of Integer)
        Get
            Return privatePredecessors
        End Get
        Private Set(ByVal value As BindingList(Of Integer))
            privatePredecessors = value
        End Set
    End Property
    Public Property Name() As String
    Public Property StartDate() As DateTime
    Public Property FinishDate() As DateTime
    Public Property Duration() As TimeSpan
    Public Property Progress() As Double
End Class

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.

  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.

csharp
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 });
                }
            }
        }
    }
}
vb
Imports DevExpress.XtraGantt
Imports System
Imports System.Data
Imports System.Globalization
Imports System.IO
Imports 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.TextFieldName = "Resources"
ganttControl1.ChartMappings.StartDateFieldName = "StartDate"
ganttControl1.ChartMappings.FinishDateFieldName = "FinishDate"

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

Dim path As String = "c:\export\project1.txt"
Dim tasks As New DataTable()
Dim dependencies As New DataTable()
PopulateDataSources(path, tasks, dependencies)
ganttControl1.DataSource = tasks
ganttControl1.DependencySource = dependencies

Public Sub PopulateDataSources(ByVal path As String, ByRef tasks As DataTable, ByRef dependencies As DataTable)
    ' Create columns for the table that contains tasks.
    Dim colId As New DataColumn("ID", GetType(String))
    Dim colParentId As New DataColumn("ParentID", GetType(String))
    Dim colText As New DataColumn("Text", GetType(String))
    Dim colStart As New DataColumn("StartDate", GetType(DateTime))
    Dim colFinish As New DataColumn("FinishDate", GetType(DateTime))
    Dim colDuration As New DataColumn("Duration", GetType(TimeSpan))
    Dim colResources As New DataColumn("Resources", GetType(String))
    Dim colWbs As New DataColumn("WBS", GetType(String))
    tasks.Columns.AddRange(New DataColumn() { colId, colParentId, colText, colStart, colFinish, colDuration, colResources, colWbs })
    ' Create columns for the table that contains dependencies.
    Dim colPredecessor As New DataColumn("PredecessorID", GetType(String))
    Dim colSuccessor As New DataColumn("SuccessorID", GetType(String))
    Dim colType As New DataColumn("Type", GetType(DevExpress.XtraGantt.DependencyType))
    dependencies.Columns.AddRange(New DataColumn() { colPredecessor, colSuccessor, colType })
    ' Read from the file.
    Using sr As New StreamReader(path)
        Do While sr.Peek() >= 0
            Dim line As String = sr.ReadLine()
            Dim values() As String = line.Split(ControlChars.Tab)
            Dim taskId As String = values(0)
            ' Get parent ID for each task
            ' from the work breakdown structure
            ' used in MS Project.
            Dim taskParentId As String = String.Empty
            Dim pathWbs() As String = values(1).Split("."c)
            If pathWbs.Length = 1 Then
                taskParentId = "0"
            Else
                Dim parentWbs As String = String.Join(".", pathWbs.Take(pathWbs.Length - 1))
                For Each row As DataRow In tasks.Rows
                    Dim rowWbs As String = DirectCast(row(colWbs), String)
                    If rowWbs = parentWbs Then
                        taskParentId = DirectCast(row(colId), String)
                    End If
                Next row
            End If
            ' Convert strings to DateTime structures.
            Dim taskStartDate As DateTime = DateTime.Parse(values(3), CultureInfo.CurrentCulture)
            Dim taskFinishDate As DateTime = DateTime.Parse(values(4), CultureInfo.CurrentCulture)
            ' This example calculates the duration
            ' instead of importing it from the file.
            Dim taskDuration As TimeSpan = taskFinishDate.Subtract(taskStartDate)
            ' Add a new row with the values to the table.
            tasks.Rows.Add(New Object() { taskId, taskParentId, values(2), taskStartDate, taskFinishDate, taskDuration, values(6), values(1) })
            Dim taskPredecessors() As String = values(5).Split(","c)
            If taskPredecessors.Length > 0 Then
                For Each value As String In taskPredecessors
                    Dim dependencyType As DependencyType = DevExpress.XtraGantt.DependencyType.FinishToStart
                    Dim predecessorId As String = value
                    If value.Contains("FS") Then
                        dependencyType = DevExpress.XtraGantt.DependencyType.FinishToStart
                        predecessorId = value.Substring(0, value.IndexOf("FS"))
                        ' This example ignores the time lag.
                        Dim timeLag As String = value.Substring(value.IndexOf("FS") + 2, value.Length - value.IndexOf("FS") - 2)
                    End If
                    If value.Contains("FF") Then
                        dependencyType = DevExpress.XtraGantt.DependencyType.FinishToFinish
                        predecessorId = value.Substring(0, value.IndexOf("FF"))
                    End If
                    If value.Contains("SS") Then
                        dependencyType = DevExpress.XtraGantt.DependencyType.StartToStart
                        predecessorId = value.Substring(0, value.IndexOf("SS"))
                    End If
                    If value.Contains("SF") Then
                        dependencyType = DevExpress.XtraGantt.DependencyType.StartToFinish
                        predecessorId = value.Substring(0, value.IndexOf("SF"))
                    End If
                    dependencies.Rows.Add(New Object() { predecessorId, taskId, dependencyType })
                Next value
            End If
        Loop
    End Using
End Sub

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:

csharp
ganttControl1.OptionsCustomization.AllowModifyTasks = DevExpress.Utils.DefaultBoolean.True;
ganttControl1.OptionsCustomization.AllowModifyProgress = DevExpress.Utils.DefaultBoolean.True;
ganttControl1.OptionsCustomization.AllowModifyDependencies = DevExpress.Utils.DefaultBoolean.True;
vb
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.

csharp
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;
}
vb
AddHandler ganttControl1.TaskMoveCompleted, AddressOf GanttControl1_TaskMoveCompleted

Private Sub GanttControl1_TaskMoveCompleted(ByVal sender As Object, ByVal e As TaskMovingEventArgs)
    If e.CurrentTaskStart < ganttControl1.Nodes(0).GetStartDate() Then
        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) <> System.Windows.Forms.DialogResult.Yes
    End If
    If e.CurrentTaskFinish > ganttControl1.Nodes(0).GetFinishDate() Then
        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) <> System.Windows.Forms.DialogResult.Yes
    End If
End Sub

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.

csharp
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;
vb
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.

csharp
ganttControl1.OptionsBehavior.ScheduleMode = DevExpress.XtraGantt.Options.ScheduleMode.Auto;
vb
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 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.

csharp
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;
}
vb
Private deadLine As New DateTime(2020, 8, 26)
Private Sub GanttControl1_CustomDrawTask(ByVal sender As Object, ByVal e As CustomDrawTaskEventArgs)
    If e.FinishDate > deadLine Then
        e.Info.Appearance.BackColor = Color.Red
    End If
End Sub

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