Background Image

GanttChartDataGrid

for WPF & .NET 4+ / .NET Core 3.1 / .NET 5+ and Silverlight™ 4+ with optional LightSwitch® extension
New: WPF .NET Core/.NET 5+ support: with NuGet!

Run demos Demo source code NuGet package Reference

GanttChartDataGrid component displays and manages tasks and dependencies using a hierarchical data grid and an attached interactive Gantt Chart accepting drag and drop operations for scheduling task bars and creating dependency lines. Supports custom appearance settings for standard, summary, and milestone tasks for the entire chart or for individual items, as needed.

Responsive in <3 sec. when loading 10,000 items on modern computers.

Screenshot
  • WPF +
    C#
    
    <pdgcc:GanttChartDataGrid x:Name="GanttChartDataGrid">
        <pdgcc:GanttChartDataGrid.Columns>
            <pdgcc:DataGridColumnCollection>
                <hdc:DataTreeGridColumn Header="Task" />
                …
            </pdgcc:DataGridColumnCollection>
        </pdgcc:GanttChartDataGrid.Columns>
        …
    </pdgcc:GanttChartDataGrid>
    
                                                
    
    var items = new ObservableCollection<GanttChartItem>
    {
        new GanttChartItem { Content = "Task 1" },
        new GanttChartItem { Content = "Task 1.1", Indentation = 1, Start = new DateTime(…), Finish = new DateTime(…), … },
        new GanttChartItem { Content = "Task 1.2", Indentation = 1, Start = new DateTime(…), Finish = new DateTime(…), … },
        new GanttChartItem { Content = "Task 2" },
        new GanttChartItem { Content = "Task 2.1", Indentation = 1, Start = new DateTime(…), Finish = new DateTime(…), … },
        new GanttChartItem { Content = "Task 2.2", Indentation = 1, … },
        new GanttChartItem { Content = "Task 2.2.1", Indentation = 2, Start = new DateTime(…), Finish = new DateTime(…), … },
        new GanttChartItem { Content = "Task 2.2.2", Indentation = 2, Start = new DateTime(…), IsMilestone = true, … },
        …
    };
    items[2].Predecessors.Add(new PredecessorItem { Item = items[1], … });
    …
    GanttChartDataGrid.Items = items;
    …
    
                                                
    Main features demo Bar templates demo
  • WPF +
    Visual Basic®
    
    <pdgcc:GanttChartDataGrid x:Name="GanttChartDataGrid">
        <pdgcc:GanttChartDataGrid.Columns>
            <pdgcc:DataGridColumnCollection>
                <hdc:DataTreeGridColumn Header="Task" />
                …
            </pdgcc:DataGridColumnCollection>
        </pdgcc:GanttChartDataGrid.Columns>
        …
    </pdgcc:GanttChartDataGrid>
    
                                                
    
    Dim items = New ObservableCollection(Of GanttChartItem) From { _
        New GanttChartItem With { .Content = "Task 1" }, _
        New GanttChartItem With { .Content = "Task 1.1", .Indentation = 1, .Start = new Date(…), .Finish = new Date(…), … }, _
        New GanttChartItem With { .Content = "Task 1.2", .Indentation = 1, .Start = new Date(…), .Finish = new Date(…), … }, _
        New GanttChartItem With { .Content = "Task 2" }, _
        New GanttChartItem With { .Content = "Task 2.1", .Indentation = 1, .Start = new Date(…), .Finish = new Date(…), … }, _
        New GanttChartItem With { .Content = "Task 2.2", .Indentation = 1, … }, _
        New GanttChartItem With { .Content = "Task 2.2.1", .Indentation = 2, .Start = new Date(…), .Finish = new Date(…), … }, _
        New GanttChartItem With { .Content = "Task 2.2.2", .Indentation = 2, .Start = new Date(…), .IsMilestone = True, … }, _
        … _
    }
    items(2).Predecessors.Add(New PredecessorItem With { .Item = items(1), … })
    …
    GanttChartDataGrid.Items = items
    …
    
                                                
    Main features demo Bar templates demo
  • Silverlight™ +
    C#
    
    <pdgcc:GanttChartDataGrid x:Name="GanttChartDataGrid">
        <pdgcc:GanttChartDataGrid.Columns>
            <pdgcc:DataGridColumnCollection>
                <hdc:DataTreeGridColumn Header="Task" />
                …
            </pdgcc:DataGridColumnCollection>
        </pdgcc:GanttChartDataGrid.Columns>
        …
    </pdgcc:GanttChartDataGrid>
    
                                                
    
    var items = new ObservableCollection<GanttChartItem>
    {
        new GanttChartItem { Content = "Task 1" },
        new GanttChartItem { Content = "Task 1.1", Indentation = 1, Start = new DateTime(…), Finish = new DateTime(…), … },
        new GanttChartItem { Content = "Task 1.2", Indentation = 1, Start = new DateTime(…), Finish = new DateTime(…), … },
        new GanttChartItem { Content = "Task 2" },
        new GanttChartItem { Content = "Task 2.1", Indentation = 1, Start = new DateTime(…), Finish = new DateTime(…), … },
        new GanttChartItem { Content = "Task 2.2", Indentation = 1, … },
        new GanttChartItem { Content = "Task 2.2.1", Indentation = 2, Start = new DateTime(…), Finish = new DateTime(…), … },
        new GanttChartItem { Content = "Task 2.2.2", Indentation = 2, Start = new DateTime(…), IsMilestone = true, … },
        …
    };
    items[2].Predecessors.Add(new PredecessorItem { Item = items[1], … });
    …
    GanttChartDataGrid.Items = items;
    …
    
                                                
    Demo LightSwitch® demo
  • Silverlight™ +
    Visual Basic®
    
    <pdgcc:GanttChartDataGrid x:Name="GanttChartDataGrid">
        <pdgcc:GanttChartDataGrid.Columns>
            <pdgcc:DataGridColumnCollection>
                <hdc:DataTreeGridColumn Header="Task" />
                …
            </pdgcc:DataGridColumnCollection>
        </pdgcc:GanttChartDataGrid.Columns>
        …
    </pdgcc:GanttChartDataGrid>
    
                                                
    
    Dim items = New ObservableCollection(Of GanttChartItem) From { _
        New GanttChartItem With { .Content = "Task 1" }, _
        New GanttChartItem With { .Content = "Task 1.1", .Indentation = 1, .Start = new Date(…), .Finish = new Date(…), … }, _
        New GanttChartItem With { .Content = "Task 1.2", .Indentation = 1, .Start = new Date(…), .Finish = new Date(…), … }, _
        New GanttChartItem With { .Content = "Task 2" }, _
        New GanttChartItem With { .Content = "Task 2.1", .Indentation = 1, .Start = new Date(…), .Finish = new Date(…), … }, _
        New GanttChartItem With { .Content = "Task 2.2", .Indentation = 1, … }, _
        New GanttChartItem With { .Content = "Task 2.2.1", .Indentation = 2, .Start = new Date(…), .Finish = new Date(…), … }, _
        New GanttChartItem With { .Content = "Task 2.2.2", .Indentation = 2, .Start = new Date(…), .IsMilestone = True, … }, _
        … _
    }
    items(2).Predecessors.Add(New PredecessorItem With { .Item = items(1), … })
    …
    GanttChartDataGrid.Items = items
    …
    
                                                
    Demo LightSwitch® demo

Items collection

To load and present data with GanttChartDataGrid control, initialize the Items collection of the component, setting up GanttChartItem objects representing timeline tasks identified by these main properties: Indentation, Content, Start, Finish, CompletedFinish, IsMilestone, AssignmentsContent, and Predecessors.

Summary items are determined by checking Indentation levels of subsequent items, and can be expanded or collapsed. Standard items are presented as rectangular bars, and milestones as special diamond shapes in the view. Completion rate of a standard item is determined by evaluating CompletedFinish value, representing the date and time up to which the effort is currently considered completed. By convention, AssignmentsContent value may be a string that specifies the resource assignments of the item with optional allocation units in classic format: Resource 1, Resource 2 [50%].

Predecessors collection (objects of type PredecessorItem) defines item dependencies and are identified by these properties: Item, DependencyType, and Lag. DependencyType may be finish-to-start, start-to-start, finish-to-finish, or start-to-finish. An optional lag time span is also supported for item dependencies. Multiple types of time constraints may also be defined for Start and Finish values of task items using special properties: MinStart, MaxStart, MinFinish, and MaxFinish.

You may set an ID or GUID for any item object as Key and GlobalKey property values, useful when mapping to relational data storage access layers. A generic Tag property is also available to support miscellaneous object linking scenarios.


var items = new ObservableCollection<GanttChartItem>
{
    new GanttChartItem { Content = "Task 1", IsExpanded = false },
    new GanttChartItem { Content = "Task 1.1", Indentation = 1, 
                         Start = new DateTime(year, month, 2, 8, 0, 0), Finish = new DateTime(year, month, 4, 16, 0, 0) },
    new GanttChartItem { Content = "Task 1.2", Indentation = 1, 
                         Start = new DateTime(year, month, 3, 8, 0, 0), Finish = new DateTime(year, month, 5, 12, 0, 0) },
    new GanttChartItem { Content = "Task 2", IsExpanded = true },
    new GanttChartItem { Content = "Task 2.1", Indentation = 1, 
                         Start = new DateTime(year, month, 2, 8, 0, 0), Finish = new DateTime(year, month, 8, 16, 0, 0), 
                         CompletedFinish = new DateTime(year, month, 5, 16, 0, 0), AssignmentsContent = "Resource 1, Resource 2 [50%]" },
    new GanttChartItem { Content = "Task 2.2", Indentation = 1 },
    new GanttChartItem { Content = "Task 2.2.1", Indentation = 2, 
                         Start = new DateTime(year, month, 11, 8, 0, 0), Finish = new DateTime(year, month, 12, 16, 0, 0), 
                         CompletedFinish = new DateTime(year, month, 12, 16, 0, 0), AssignmentsContent = "Resource 2" },
    new GanttChartItem { Content = "Task 2.2.2", Indentation = 2, 
                         Start = new DateTime(year, month, 12, 12, 0, 0), Finish = new DateTime(year, month, 14, 16, 0, 0), 
                         AssignmentsContent = "Resource 2" },
    new GanttChartItem { Content = "Task 3", Indentation = 1, 
                         Start = new DateTime(year, month, 15, 16, 0, 0), IsMilestone = true }
};
items[3].Predecessors.Add(new PredecessorItem { Item = items[0], DependencyType = DependencyType.StartStart });
items[7].Predecessors.Add(new PredecessorItem { Item = items[6], Lag = TimeSpan.FromHours(2) });
items[8].Predecessors.Add(new PredecessorItem { Item = items[4] });
items[8].Predecessors.Add(new PredecessorItem { Item = items[5] });
GanttChartDataGrid.Items = items;

                        

Drag and drop

End users may use drag and drop operations to reschedule bars, update start, finish and completion values independently, and create all types of dependencies between items directly from the chart area.

Edit and Undo operations

Copy and Paste operations are available as built-in features of the component. Data is copied to the Clipboard as tab separated values so they may be easily pasted into Microsoft Excel® sheets or other applications with tabular data import support. Move, MoveUp, and MoveDown operations allow moving selected items in the hierarchy, with or without child items. You may even configure a Thumb element in a column cell template definition to allow visual drag and drop operations for moving items around.

A built-in undo queue is available, with Undo and Redo operations that may be easily called from code.

Performance

We have designed the component to achieve maximum runtime performance, loading and displaying thousands of items while remaining highly responsive. The control has IsAsyncPresentationEnabled and IsVirtualizing properties set to true by default, so asynchronous data loading and user interface virtualization are turned on unless you set them off manually.

Timeline and calendars

You may configure timeline duration, visible and working days and hours, scales, update interval (for drag and drop operations), and zoom level (width of an hour) in the view. The component can further be zoomed in and out by moving the mouse wheel. Nonworking intervals, such as holidays or simple day breaks, may be defined either as a collection or using a delegate.

When the end user horizontally scrolls to an end of the timeline viewport special buttons appear to allow updating the timeline page, increasing both start and finish ends synchronously. The component also supports automatic zooming, depending on the set up timeline page. Otherwise, the timeline is automatically scrolled horizontally to the start time of a selected task when that date and time is within the set up timeline page.

You can configure working and nonworking time for individual items, when needed, using Schedule objects. Actually, a general calendar may also be provided this way, by setting the Schedule property of the component itself. An individual item may have more or less working time than configured at view level, and therefore they will behave differently when setting start and finish values, including when using drag and drop update operations.

If you need to, you can also generate numeric scales, abstracting out the concrete date and times to generic values. Or zoom in to display hours and minutes and with similar code you can display milliseconds too, or – why not? – even zoom out to centuries. Recurrence functionality may also be an interesting feature to implement for your items.

Screenshot Screenshot Screenshot Screenshot
  • WPF
    
    <pdgcc:GanttChartDataGrid x:Name="GanttChartDataGrid" HourWidth="20" HeaderHeight="60" ScaleHeaderHeight="20" >
        <!-- Set Scales collection to specify the headers to be displayed in the chart. -->
        <pdgcc:GanttChartDataGrid.Scales>
            <pdgcc:ScaleCollection>
                <pdgcc:Scale ScaleType="Months" HeaderBorderBrush="Silver" HeaderBorderThickness="0,0,1,1" 
                             HeaderContentTemplate="{StaticResource ScaleHeaderContentTemplate}" BorderBrush="Silver" BorderThickness="0,0,1,0"/>
                <pdgcc:Scale ScaleType="Weeks" HeaderHeight="0" BorderBrush="Silver" BorderThickness="0,0,0.35,0"/>
                <pdgcc:Scale ScaleType="Days" HeaderContentFormat="DayLeadingZero" … />
                <pdgcc:Scale ScaleType="Hours" HeaderContentTemplate="{StaticResource ScaleHeaderContentTemplate}" … />
            </pdgcc:ScaleCollection>
        </pdgcc:GanttChartDataGrid.Scales>
        …
    </pdgcc:GanttChartDataGrid>
    
                                            
    
    GanttChartDataGrid.SetTimelinePage(start, finish);
    // Optionally, enable automatic zoom level based on timeline page:
    GanttChartDataGrid.IsFittingToTimelinePageEnabled = true;
    
                                            
    
    GanttChartDataGrid.VisibleWeekStart = DayOfWeek.Monday;
    GanttChartDataGrid.VisibleWeekFinish = DayOfWeek.Friday; // Mon-Fri
    GanttChartDataGrid.WorkingWeekStart = DayOfWeek.Monday;
    GanttChartDataGrid.WorkingWeekFinish = DayOfWeek.Thursday; // Mon-Thu
    GanttChartDataGrid.WorkingDayStart = TimeSpan.FromHours(10);
    GanttChartDataGrid.WorkingDayFinish = TimeSpan.FromHours(19); // 10-19
    GanttChartDataGrid.NonworkingIntervals = …;
    
                                            
    
    GanttChartDataGrid.Schedule = new Schedule(…);
    item.Schedule = new Schedule(…);
    
                                            
    Custom schedule demo Numeric days demo Minute scale demo Recurrence demo
  • Silverlight™
    
    <pdgcc:GanttChartDataGrid x:Name="GanttChartDataGrid" HourWidth="20" HeaderHeight="60" ScaleHeaderHeight="20" >
        <!-- Set Scales collection to specify the headers to be displayed in the chart. -->
        <pdgcc:GanttChartDataGrid.Scales>
            <pdgcc:ScaleCollection>
                <pdgcc:Scale ScaleType="Months" HeaderBorderBrush="Silver" HeaderBorderThickness="0,0,1,1" 
                             HeaderContentTemplate="{StaticResource ScaleHeaderContentTemplate}" BorderBrush="Silver" BorderThickness="0,0,1,0"/>
                <pdgcc:Scale ScaleType="Weeks" HeaderHeight="0" BorderBrush="Silver" BorderThickness="0,0,0.35,0"/>
                <pdgcc:Scale ScaleType="Days" HeaderContentFormat="DayLeadingZero" … />
                <pdgcc:Scale ScaleType="Hours" HeaderContentTemplate="{StaticResource ScaleHeaderContentTemplate}" … />
            </pdgcc:ScaleCollection>
        </pdgcc:GanttChartDataGrid.Scales>
        …
    </pdgcc:GanttChartDataGrid>
    
                                            
    
    GanttChartDataGrid.SetTimelinePage(start, finish);
    // Optionally, enable automatic zoom level based on timeline page:
    GanttChartDataGrid.IsFittingToTimelinePageEnabled = true;
    
                                            
    
    GanttChartDataGrid.VisibleWeekStart = DayOfWeek.Monday;
    GanttChartDataGrid.VisibleWeekFinish = DayOfWeek.Friday; // Mon-Fri
    GanttChartDataGrid.WorkingWeekStart = DayOfWeek.Monday;
    GanttChartDataGrid.WorkingWeekFinish = DayOfWeek.Thursday; // Mon-Thu
    GanttChartDataGrid.WorkingDayStart = TimeSpan.FromHours(10);
    GanttChartDataGrid.WorkingDayFinish = TimeSpan.FromHours(19); // 10-19
    GanttChartDataGrid.NonworkingIntervals = …;
    
                                            
    
    GanttChartDataGrid.Schedule = new Schedule(…);
    item.Schedule = new Schedule(…);
    
                                            
    Custom schedule demo Numeric days demo Minute scale demo Recurrence demo

Project management features and Microsoft® Project compatibility

Besides data visualization features, the component offers built-in computed properties such as Duration, Effort, CompletedEffort, Completion, Cost, etc., project management algorithms such as baseline initialization and visualization, auto scheduling, critical path enumeration, work optimization, and allocation and resource leveling, optionally based on pre-initialized generic or individual resource usage costs and material resource quantities.

The component supports loading and saving data in Microsoft Project® XML format with LoadProjectXml and SaveProjectXml methods, allowing you to import and export Microsoft Project® files with ease.

Moreover, ProjectXmlSerializer offers support for further customizing the way actual loading and saving operations occur, allowing you to inject custom code for XML parsing and generation with handler methods on specific events.


var effort = item.TotalEffort; 
var percentCompleted = item.Completion * 100;
GanttChartDataGrid.SetupBaseline(); GanttChartDataGrid.IsBaselineVisible = true; 
GanttChartDataGrid.AreTaskDependencyConstraintsEnabled = true;
foreach (criticalItem in GanttChartDataGrid.GetCriticalItems()) { … }
GanttChartDataGrid.SpecificResourceHourCosts = …;
GanttChartDataGrid.ResourceQuantities = …;
GanttChartDataGrid.OptimizeWork();
GanttChartDataGrid.LevelAllocations(); 
GanttChartDataGrid.LevelResources();

                        

var projectXml = GanttChartDataGrid.GetProjectXml();
GanttChartDataGrid.LoadProjectXml(projectXml);

                        
Reference

Microsoft® Excel adapter

Using Project XML formatted content as input, you can also use DlhSoft's ProjectManagementXlsx Adapter API (open source) to generate Excel® files and share task information with more ease. And, of course, you import tasks from an Excel® sheet through Microsoft® Project XML format back into a Gantt Chart component, too.

Excel® serialization support is available as well through a separate NuGet package.

The adapter requires a license for Project Management Framework. Light Library licensees can order a free license for the secondary product.


var excelBytes = File.ReadAllBytes(source);
var projectXml = ProjectManagementXslx.Adapter.GetProjectXml(excelBytes);

                        

var projectXml = Encoding.UTF8.GetString(File.ReadAllBytes(source));
var excelBytes = ProjectManagementXslx.Adapter.GetExcelBytes(projectXml);

                        
Converter demo

Data binding

Although we designed the component to support items of specific types only (GanttChartItem) to ensure high runtime performance, you may use our built-in collection converter (TaskItemsConverter) to set up data binding to custom collection types with ease. Alternatively, you can use a fully custom converter to provide collection synchronization upon your own needs.

The component is persistence layer independent, so you can bind it to data collections from virtually any data source, including but not limited to SQL Server® databases.

  • WPF
    
    <pdgcc:GanttChartDataGrid>
        <pdgcc:GanttChartDataGrid.Items>
            <Binding>
                <Binding.Converter>
                    <!-- Set *Member properties to identify custom item properties that need to be internally bound. -->
                    <!-- Optionally, set UpdateTargetOnSourceChanges and/or UpdateSourceOnTargetChanges to true/false as needed. -->
                    <pdgcc:TaskItemsConverter ContentMember="Name" IndentationMember="IndentLevel" StartMember="StartDate" 
                                              FinishMember="FinishDate" CompletedFinishMember="CompletionCurrentDate" IsMilestoneMember="Milestone"
                                              PredecessorsMember="Predecessors" PredecessorItemMember="Reference" PredecessorDependencyTypeMember="Type"
                                              AssignmentsContentMember="AssignmentsString" />
                </Binding.Converter>
            </Binding>
        </pdgcc:GanttChartDataGrid.Items>
        <pdgcc:GanttChartDataGrid.Columns>
            <!-- Define new columns for custom properties, using Tag prefix to refer the original custom data item properties. -->
            <DataGridTextColumn Header="Description" Binding="{Binding Tag.Description, Mode=TwoWay}" IsReadOnly="False" />
        </pdgcc:GanttChartDataGrid.Columns>
    </pdgcc:GanttChartDataGrid>
    
                                                
    
    var items = new ObservableCollection<CustomTaskItem>
    {
        new CustomTaskItem { Name = "Task 1", Description = "Description of custom task 1" },
        new CustomTaskItem { Name = "Task 1.1", IndentLevel = 1, StartDate = DateTime.Today.Add(TimeSpan.Parse("08:00:00")), FinishDate = DateTime.Today.Add(TimeSpan.Parse("16:00:00")), CompletionCurrentDate = DateTime.Today.Add(TimeSpan.Parse("12:00:00")), AssignmentsString = "Resource 1",  Description = "Description of custom task 1.1" },
        new CustomTaskItem { Name = "Task 1.2", IndentLevel = 1, StartDate = DateTime.Today.AddDays(1).Add(TimeSpan.Parse("08:00:00")), FinishDate = DateTime.Today.AddDays(2).Add(TimeSpan.Parse("16:00:00")), AssignmentsString = "Resource 1, Resource 2", Description = "Description of custom task 1.2" },
        new CustomTaskItem { Name = "Task 2", Description = "Description of custom task 2" },
        new CustomTaskItem { Name = "Task 2.1", IndentLevel = 1, StartDate = DateTime.Today.Add(TimeSpan.Parse("08:00:00")), FinishDate = DateTime.Today.AddDays(2).Add(TimeSpan.Parse("12:00:00")), Description = "Description of custom task 2.1" },
        new CustomTaskItem { Name = "Task 2.2", IndentLevel = 1, StartDate = DateTime.Today.Add(TimeSpan.Parse("08:00:00")), FinishDate = DateTime.Today.AddDays(3).Add(TimeSpan.Parse("12:00:00")), Description = "Description of custom task 2.2" },
        new CustomTaskItem { Name = "Task 3", IndentLevel = 0, StartDate = DateTime.Today.AddDays(5), Milestone = true, Description = "Description of custom task 3" }
    };
    items[2].Predecessors = new ObservableCollection<CustomPredecessorItem> { new CustomPredecessorItem { Reference = taskItems[1] } };
    items[3].Predecessors = new ObservableCollection<CustomPredecessorItem> { new CustomPredecessorItem { Reference = taskItems[0], Type = (int)DependencyType.StartStart } };
    items[6].Predecessors = new ObservableCollection<CustomPredecessorItem> { new CustomPredecessorItem { Reference = taskItems[0] }, new CustomPredecessorItem { Reference = taskItems[3] } };
    DataContext = items;
    
                                                
    Binding demo Custom converter demo Database demo
  • Silverlight™
    
    <pdgcc:GanttChartDataGrid>
        <pdgcc:GanttChartDataGrid.Items>
            <Binding>
                <Binding.Converter>
                    <!-- Set *Member properties to identify custom item properties that need to be internally bound. -->
                    <!-- Optionally, set UpdateTargetOnSourceChanges and/or UpdateSourceOnTargetChanges to true/false as needed. -->
                    <pdgcc:TaskItemsConverter ContentMember="Name" IndentationMember="IndentLevel" StartMember="StartDate" 
                                              FinishMember="FinishDate" CompletedFinishMember="CompletionCurrentDate" IsMilestoneMember="Milestone"
                                              PredecessorsMember="Predecessors" PredecessorItemMember="Reference" PredecessorDependencyTypeMember="Type"
                                              AssignmentsContentMember="AssignmentsString" />
                </Binding.Converter>
            </Binding>
        </pdgcc:GanttChartDataGrid.Items>
        <pdgcc:GanttChartDataGrid.Columns>
            <!-- Define new columns for custom properties, using Tag prefix to refer the original custom data item properties. -->
            <d:DataGridTextColumn Header="Description" Binding="{Binding Tag.Description, Mode=TwoWay}" IsReadOnly="False" />
        </pdgcc:GanttChartDataGrid.Columns>
    </pdgcc:GanttChartDataGrid>
    
                                                
    
    var items = new ObservableCollection<CustomTaskItem>
    {
        new CustomTaskItem { Name = "Task 1", Description = "Description of custom task 1" },
        new CustomTaskItem { Name = "Task 1.1", IndentLevel = 1, StartDate = DateTime.Today.Add(TimeSpan.Parse("08:00:00")), FinishDate = DateTime.Today.Add(TimeSpan.Parse("16:00:00")), CompletionCurrentDate = DateTime.Today.Add(TimeSpan.Parse("12:00:00")), AssignmentsString = "Resource 1",  Description = "Description of custom task 1.1" },
        new CustomTaskItem { Name = "Task 1.2", IndentLevel = 1, StartDate = DateTime.Today.AddDays(1).Add(TimeSpan.Parse("08:00:00")), FinishDate = DateTime.Today.AddDays(2).Add(TimeSpan.Parse("16:00:00")), AssignmentsString = "Resource 1, Resource 2", Description = "Description of custom task 1.2" },
        new CustomTaskItem { Name = "Task 2", Description = "Description of custom task 2" },
        new CustomTaskItem { Name = "Task 2.1", IndentLevel = 1, StartDate = DateTime.Today.Add(TimeSpan.Parse("08:00:00")), FinishDate = DateTime.Today.AddDays(2).Add(TimeSpan.Parse("12:00:00")), Description = "Description of custom task 2.1" },
        new CustomTaskItem { Name = "Task 2.2", IndentLevel = 1, StartDate = DateTime.Today.Add(TimeSpan.Parse("08:00:00")), FinishDate = DateTime.Today.AddDays(3).Add(TimeSpan.Parse("12:00:00")), Description = "Description of custom task 2.2" },
        new CustomTaskItem { Name = "Task 3", IndentLevel = 0, StartDate = DateTime.Today.AddDays(5), Milestone = true, Description = "Description of custom task 3" }
    };
    items[2].Predecessors = new ObservableCollection<CustomPredecessorItem> { new CustomPredecessorItem { Reference = taskItems[1] } };
    items[3].Predecessors = new ObservableCollection<CustomPredecessorItem> { new CustomPredecessorItem { Reference = taskItems[0], Type = (int)DependencyType.StartStart } };
    items[6].Predecessors = new ObservableCollection<CustomPredecessorItem> { new CustomPredecessorItem { Reference = taskItems[0] }, new CustomPredecessorItem { Reference = taskItems[3] } };
    DataContext = items;
    
                                                
    Binding demo Custom converter demo Database demo

Grid columns, row filtering, sorting, summary aggregation, and changes

You may customize the column collection of the grid by adding or redesigning data bound and cell template based columns. You may sort and filter items out hierarchically using Sort method of the component and by setting item.IsHidden values to true.

Date and time and time span columns may use built-in converters optionally with custom parameters to enable special cell value formatting both when displaying or editing values in the grid. For example, if you set ConverterParameter of a DurationStringConverter instance to 0.##d/8, it will present time spans in working days, assuming a day has 8 work hours.

You can use a TextBox for a Predecessors column when binding to PredecessorsString property, but we offer a specialized AssignmentComboBox (and an AssignmentListBox) for binding an Assignments column to the AssignmentsString item property. IndexString property may be used to present task indexes on screen, helping the end user define predecessors. Supplementary, we also offer built-in WBS indexing support through the WbsIndexString item property.

To be notified when items managed by the component change, simply handle the ItemCollectionChanged and ItemPropertyChanged events.

Optionally, you can also initialize custom property value aggregation for summary items or change the component behavior to display child items on the same line when summary items are collapsed.

Screenshot Screenshot Screenshot
  • WPF
    
    <pdgcc:GanttChartDataGrid>
        <pdgcc:GanttChartDataGrid.Columns>
            <pdgcc:DataGridColumnCollection>
                <hdc:DataTreeGridColumn Header="Task" MinWidth="160"/>
                <DataGridTemplateColumn Header="Start" MinWidth="140">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ContentControl Content="{Binding Start, Converter={StaticResource DateTimeStringConverter}, ConverterParameter=g}" Padding="4"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                    <DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <DatePicker SelectedDate="{Binding Start, Mode=TwoWay}" IsEnabled="{Binding IsLeaf}" Padding="0"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellEditingTemplate>
                </DataGridTemplateColumn>
                <DataGridTemplateColumn Header="Effort" MinWidth="50">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ContentControl Content="{Binding TotalEffort, Converter={StaticResource DurationStringConverter}, ConverterParameter=0.##h}" Padding="4"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                    <DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <TextBox Text="{Binding TotalEffort, Converter={StaticResource DurationStringConverter}, ConverterParameter=0.##h, Mode=TwoWay}" IsReadOnly="{Binding HasChildren}" BorderThickness="0" Padding="0"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellEditingTemplate>
                </DataGridTemplateColumn>
                …
            </pdgcc:DataGridColumnCollection>
        </pdgcc:GanttChartDataGrid.Columns>
    </pdgcc:GanttChartDataGrid>
    
                                            
    Hierarchical sorting demo Filtering rows demo Summary value aggregation demo Summary bars demo Change notifications demo
  • Silverlight™
    
    <pdgcc:GanttChartDataGrid>
        <pdgcc:GanttChartDataGrid.Columns>
            <pdgcc:DataGridColumnCollection>
                <hdc:DataTreeGridColumn Header="Task" MinWidth="160"/>
                <d:DataGridTemplateColumn Header="Start" MinWidth="140">
                    <d:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ContentControl Content="{Binding Start, Converter={StaticResource DateTimeStringConverter}, ConverterParameter=g}" Padding="4"/>
                        </DataTemplate>
                    </d:DataGridTemplateColumn.CellTemplate>
                    <d:DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <DatePicker SelectedDate="{Binding Start, Mode=TwoWay}" IsEnabled="{Binding IsLeaf}" Padding="0"/>
                        </DataTemplate>
                    </d:DataGridTemplateColumn.CellEditingTemplate>
                </d:DataGridTemplateColumn>
                <d:DataGridTemplateColumn Header="Effort" MinWidth="50">
                    <d:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ContentControl Content="{Binding TotalEffort, Converter={StaticResource DurationStringConverter}, ConverterParameter=0.##h}" Padding="4"/>
                        </DataTemplate>
                    </d:DataGridTemplateColumn.CellTemplate>
                    <d:DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <TextBox Text="{Binding TotalEffort, Converter={StaticResource DurationStringConverter}, ConverterParameter=0.##h, Mode=TwoWay}" IsReadOnly="{Binding HasChildren}" BorderThickness="0" Padding="0"/>
                        </DataTemplate>
                    </d:DataGridTemplateColumn.CellEditingTemplate>
                </d:DataGridTemplateColumn>
                …
            </pdgcc:DataGridColumnCollection>
        </pdgcc:GanttChartDataGrid.Columns>
    </pdgcc:GanttChartDataGrid>
    
                                            
    Hierarchical sorting demo Filtering rows demo Summary value aggregation demo Summary bars demo Change notifications demo

Appearance and bar templates

You may fully customize item appearance, either for the entire chart or for individual entries in the view, using attached properties such as GanttChartView.StandardBarFill, StandardBarStroke, MilestoneBarFill, etc. Moreover, you may easily set up an AlternatingItemBackground brush for both the grid and chart areas, and ItemBackground and ItemForeground properties also apply to both areas for any individual item that needs to be highlighted in the view.

When you need to develop advanced features in your timeline based application, chart bars may be fully redesigned using XAML based templates for StandardTaskTemplate, SummaryTaskTemplate, and MilestoneTaskTemplate properties of the component.

And if you need to customize component input interactions, you may handle mouse events and get information about the visually hit elements with ease.

Screenshot Screenshot

Printing and image exporting

The component offers a Print method that may be called to initiate a direct print operation for its content. A custom PrintingTemplate definition that you can specify using XAML is repeatedly used when generating the printed pages.

Moreover, you can export scalable images of the component content by calling GetBitmapSource method on the fly. For example, you may then encode an output image to an external file format such as PNG, include the image into an element displayed in a custom printed document, or simply displaying it as read only content on the screen.


GanttChartDataGrid.Print("Sample Document");

                        

GanttChartDataGrid.Export((Action)delegate
{
    SaveFileDialog saveFileDialog = 
        new SaveFileDialog { Title = "Export Image To", Filter = "PNG image files|*.png" };
    if (saveFileDialog.ShowDialog() != true)
        return;
    BitmapSource bitmapSource = GanttChartDataGrid.GetExportBitmapSource(96 * 2);
    using (Stream stream = saveFileDialog.OpenFile())
    {
        PngBitmapEncoder pngBitmapEncoder = new PngBitmapEncoder();
        pngBitmapEncoder.Frames.Add(BitmapFrame.Create(bitmapSource));
        pngBitmapEncoder.Save(stream);
    }
});

                        

Windows® Forms

You may use the WPF component in Windows® Forms applications using Microsoft® ElementHost control from WindowsFormsIntegration assembly of .NET 4+.

Optionally, you can define a XAML user control in your Windows® Forms project to serve for encapsulation.


var items = …;
var host = new ElementHost 
{ 
    Child = new GanttChartDataGrid 
    { 
        Items = items,
        …
    }, 
    Dock = DockStyle.Fill 
};
Controls.Add(host);

                        
Windows® Forms demo