Log in to like this post! How to Start Using Infragistics XamGantt Control [Infragistics] Mihail Mateev / Sunday, October 7, 2012 The xamGantt control is a cross platform control that provides a user interface similar to the Microsoft Project 2010. You can create, edit and visualize your project plan, create deadlines, milestones and set dependencies between tasks using the xamGantt control. The control’s scheduling engine performs calculations on every edit to keep the plan up to date. In a series of several articles you can read the Infragistics Gantt Chart, beginning with an introduction and going to the details and tricks. Probably the most important information for developers is how to start to use a specific control and how to integrate their applications. This blog is exactly as an introduction how to start working with Infragistics XamGantt control. I hope after this article programmers will have fun with this component. Infragistics Gantt Control helps to create own project planning applications, that can contain most of the Microsoft Project features. Using Infragistics NetAdvantage for XAML (WPF and Silverlight) Vol. 12.2 you can create software for project-management teams providing the benefit from the next NetAdvantage updates of and features . To be possible to start with Gantt Chart control you need to know how to: Add XamGantt to your application Gantt Control Data Binding Set Gant Chart Settings Create a Project Create Tasks- using code- using user interaction Edit Task Delete Task Adding XamGantt to your application A project should has the following required references: InfragisticsWPF4.Controls.Editors.XamCalendar.dll InfragisticsWPF4.Controls.Grids.XamGrid.dll InfragisticsSL.Controls.Interactions.XamDialogWindow.dll (Only required for Silverlight projects) InfragisticsWPF4.Controls.Menus.XamMenu.dll InfragisticsWPF4.Controls.Schedules.dll InfragisticsWPF4.Controls.Schedules.XamGantt.dll InfragisticsWPF.DataManager.dll (Only required for WPF projects) InfragisticsWPF4.dll If you want to use Gantt control from Visual Studio toolbox all references will be added automatically. Infragistics Gantt Control Data Binding The XamGantt control provides two options for data binding: Via the XamGantt Project property set to a Project instance Via the ListBackedProject and its TaskItemsSource property set to arbitrary custom tasks collection Binding to Arbitrary Tasks Collection Using ListBackedProject In many real life cases you can have own model for the tasks (for example when we have data stored in database and use ORM to create classes for your model) The XamGantt control can be bound to a collection of custom tasks. In this case, create an instance of ListBackedProject and set it to the XamGantt Project property. To be possible to use custom tasks you need to: Create a custom task Model class Create a ViewModel class Create a ListBackedProject and bind it to data Create project task property to custom task property mappings Set the XamGantt Project property to the created ListBackedProject Create a custom task Model class Create an additional class named ObservableModel, that implements INotifyPropertyChanged 1: public class ObservableModel : INotifyPropertyChanged 2: { 3: #region NotifyPropertyChanged 4: public event PropertyChangedEventHandler PropertyChanged; 5: protected void NotifyPropertyChanged(String info) 6: { 7: if (PropertyChanged != null) 8: { 9: PropertyChanged(this, new PropertyChangedEventArgs(info)); 10: } 11: } 12: #endregion NotifyPropertyChanged 13: } Create a custom task model 1: class TaskModel : ObservableModel 2: { 3: #region ConstraintType 4: private ProjectTaskConstraintType _constraintType; 5: public ProjectTaskConstraintType ConstraintType 6: { 7: get 8: { 9: return _constraintType; 10: } 11: set 12: { 13: if (_constraintType != value) 14: { 15: _constraintType = value; 16: this.NotifyPropertyChanged("ConstraintType"); 17: } 18: } 19: } 20: #endregion ConstraintType 21: 22: #region ConstraintDate 23: private DateTime _constraintDate; 24: public DateTime ConstraintDate 25: { 26: get 27: { 28: return _constraintDate; 29: } 30: set 31: { 32: if (_constraintDate != value) 33: { 34: _constraintDate = value; 35: this.NotifyPropertyChanged("ConstraintDate"); 36: } 37: } 38: } 39: #endregion ConstraintDate 40: 41: #region DeadlineDate 42: private DateTime? _deadlineDate; 43: public DateTime? DeadlineDate 44: { 45: get 46: { 47: return _deadlineDate; 48: } 49: set 50: { 51: if (_deadlineDate != value) 52: { 53: _deadlineDate = value; 54: this.NotifyPropertyChanged("DeadlineDate"); 55: } 56: } 57: } 58: #endregion //DeadlineDate 59: 60: #region DurationFormat 61: private ProjectDurationFormat _durationFormat; 62: public ProjectDurationFormat DurationFormat 63: { 64: get 65: { 66: return _durationFormat; 67: } 68: set 69: { 70: if (_durationFormat != value) 71: { 72: _durationFormat = value; 73: this.NotifyPropertyChanged("DurationFormat"); 74: } 75: } 76: } 77: #endregion DurationFormat 78: 79: #region Duration 80: private TimeSpan _duration; 81: public TimeSpan Duration 82: { 83: get 84: { 85: return _duration; 86: } 87: set 88: { 89: if (_duration != value) 90: { 91: _duration = value; 92: this.NotifyPropertyChanged("Duration"); 93: } 94: } 95: } 96: #endregion Duration 97: 98: #region IsMilestone 99: private bool _isMilestone = false; 100: public bool IsMilestone 101: { 102: get 103: { 104: return _isMilestone; 105: } 106: set 107: { 108: if (_isMilestone != value) 109: { 110: _isMilestone = value; 111: this.NotifyPropertyChanged("IsMilestone"); 112: } 113: } 114: } 115: #endregion IsMilestone 116: 117: #region IsInProgress 118: private bool _isInProgress = true; 119: public bool IsInProgress 120: { 121: get 122: { 123: return _isInProgress; 124: } 125: set 126: { 127: if (_isInProgress != value) 128: { 129: _isInProgress = value; 130: this.NotifyPropertyChanged("IsInProgress"); 131: } 132: } 133: } 134: #endregion IsInProgress 135: 136: #region IsUndetermined 137: private bool _isUndetermined = false; 138: public bool IsUndetermined 139: { 140: get 141: { 142: return _isUndetermined; 143: } 144: set 145: { 146: if (_isUndetermined != value) 147: { 148: _isUndetermined = value; 149: this.NotifyPropertyChanged("IsUndetermined"); 150: } 151: } 152: } 153: #endregion //IsUndetermined 154: 155: #region Predecessors 156: private string _predecesors; 157: public string Predecessors 158: { 159: get { return _predecesors; } 160: set 161: { 162: if (value != _predecesors) 163: { 164: _predecesors = value; 165: this.NotifyPropertyChanged("Predecessors"); 166: } 167: } 168: } 169: #endregion //Predecessors 170: 171: #region Successors 172: private string _successors; 173: public string Successors 174: { 175: get { return _successors; } 176: set 177: { 178: if (value != _successors) 179: { 180: _successors = value; 181: this.NotifyPropertyChanged("Successors"); 182: } 183: } 184: } 185: #endregion //Successors 186: 187: #region Start 188: private DateTime _start; 189: public DateTime Start 190: { 191: get 192: { 193: return _start; 194: } 195: set 196: { 197: if (_start != value) 198: { 199: _start = value; 200: this.NotifyPropertyChanged("Start"); 201: } 202: } 203: } 204: #endregion Start 205: 206: 207: #region TaskID 208: private string _taskId; 209: public string TaskID 210: { 211: get 212: { 213: return _taskId; 214: } 215: set 216: { 217: if (_taskId != value) 218: { 219: _taskId = value; 220: this.NotifyPropertyChanged("TaskID"); 221: } 222: } 223: } 224: #endregion TaskID 225: 226: #region Tasks 227: private string _tasks; 228: public string Tasks 229: { 230: get 231: { 232: return _tasks; 233: } 234: set 235: { 236: if (_tasks != value) 237: { 238: _tasks = value; 239: this.NotifyPropertyChanged("Tasks"); 240: } 241: } 242: } 243: #endregion Tasks 244: 245: #region TaskName 246: private string _name; 247: public string TaskName 248: { 249: get 250: { 251: return _name; 252: } 253: set 254: { 255: if (_name != value) 256: { 257: _name = value; 258: this.NotifyPropertyChanged("TaskName"); 259: } 260: } 261: } 262: #endregion TaskName 263: 264: #region ResourceName 265: private string _resourceName; 266: public string ResourceName 267: { 268: get 269: { 270: return _resourceName; 271: } 272: set 273: { 274: if (_resourceName != value) 275: { 276: _resourceName = value; 277: this.NotifyPropertyChanged("ResourceName"); 278: } 279: } 280: } 281: #endregion ResourceName 282: 283: } Implement a ViewModel to present the whole project and the selected task in a Gantt control 1: class ProjectViewModel : ObservableModel 2: { 3: #region Constructor 4: public ProjectViewModel() 5: { 6: this.Tasks = new ObservableCollection(); 7: } 8: #endregion Constructor 9: 10: #region SelectedTask 11: private TaskModel _selectedTask; 12: public TaskModel SelectedTask 13: { 14: get 15: { 16: return _selectedTask; 17: } 18: set 19: { 20: if (value != null) 21: { 22: _selectedTask = value; 23: } 24: 25: NotifyPropertyChanged("SelectedTask"); 26: } 27: } 28: #endregion SelectedTask 29: 30: #region Tasks 31: private ObservableCollection _tasks; 32: public ObservableCollection Tasks 33: { 34: get 35: { 36: return _tasks; 37: } 38: set 39: { 40: if (value != null) 41: { 42: _tasks = value; 43: } 44: 45: NotifyPropertyChanged("Tasks"); 46: } 47: } 48: #endregion //Tasks 49: 50: } Create a ListBackedProject and bind it to data 1: <ig:ListBackedProject x:Name="dataProvider" TaskItemsSource="{Binding Tasks}"> 2: <ig:ListBackedProject.TaskPropertyMappings> 3: <ig:ProjectTaskPropertyMappingCollection UseDefaultMappings="True"> 4: 5: 6: 7: 8: ig:ProjectTaskPropertyMappingCollection> 9: ig:ListBackedProject.TaskPropertyMappings> 10: <ig:ListBackedProject.TaskSettings> 11: <ig:ProjectTaskSettings AllowChangeIndentation="True" 12: AllowDelete="True" 13: AllowDragDeadline="True" 14: AllowDragMilestone="True" 15: AllowDragPercentComplete="True" 16: AllowDragSummary="Always" 17: AllowDragTask="True" 18: AllowInsert="True" 19: AllowResizeSummary="Always" 20: AllowResizeTask="True"/> 21: ig:ListBackedProject.TaskSettings> 22: 23: ig:ListBackedProject> Set XamGantt Column Settings (optional) These settings are used to define how to maintain task settings in Gantt control 1: <ig:XamGantt Margin="10" x:Name="xamGantt" VerticalAlignment="Top" ActiveCellChanged="xamGantt_ActiveCellChanged" Project="{Binding ElementName=dataProvider}"> 2: <ig:XamGantt.DefaultColumnSettings> 3: <ig:ProjectColumnSettings AllowHide="True" 4: AllowMove="True" 5: AllowResize="True" 6: AllowShow="True" /> 7: ig:XamGantt.DefaultColumnSettings> 8: ig:XamGantt> Create a mappings collection using TaskPropertyMappings In every ProjectTaskPropertyMapping, the TaskProperty specifies a ProjectTask property and the DataObjectProperty specifies the corresponding custom task property. Mandatory Mappings: The following mappings are mandatory: DataItemId – to uniquely identify the task Tasks – to store the child tasks of a task ConstraintType/ConstraintDate DurationFormat – to specify the units for the duration and to track whether the duration is an elapsed duration. 1: 2: <ig:ProjectTaskPropertyMapping TaskProperty="DataItemId" 3: DataObjectProperty="TaskID" /> 4: <ig:ProjectTaskPropertyMapping TaskProperty="ConstraintType" 5: DataObjectProperty="ConstraintType" /> 8: <ig:ProjectTaskPropertyMapping TaskProperty="DurationFormat" 9: DataObjectProperty="DurationFormat" /> 10: <ig:ProjectTaskPropertyMapping TaskProperty="Tasks" 11: DataObjectProperty="Tasks" /> 12: Mandatory mappings are required to have an own project ViewModel with custom task. These mapping don’t allow to maintain tasks activation and to schedule manually tasks. Schedule manually tasks in the project. To support manual tasks scheduling you need to map property from your custom task model to IsManual property from ProjectTask class 1: 2: 3: <ig:ProjectTaskPropertyMapping TaskProperty="IsManual" 4: DataObjectProperty="IsUndetermined" /> 5: 6: In this case you can change the state of the task schedule between manual and automatic. Maintain task active/inactive state You need to map ProjectTask.IsActive property to a property from your custom task model 1: 2: 3: <ig:ProjectTaskPropertyMapping TaskProperty="IsActive" 4: DataObjectProperty="IsInProgress" /> 5: 6: In this case you can change the state of the task schedule between manual and automatic. Other task property mappings. The sample below shows other property mappings. If you need to change some task properties via ViewModel you need to implement an appropriate mapping. 1: <ig:ListBackedProject.TaskPropertyMappings> 2: <ig:ProjectTaskPropertyMappingCollection UseDefaultMappings="True"> 3: 4: 5: <ig:ProjectTaskPropertyMapping TaskProperty="DataItemId" 6: DataObjectProperty="TaskID" /> 7: <ig:ProjectTaskPropertyMapping TaskProperty="ConstraintType" 8: DataObjectProperty="ConstraintType" /> 9: <ig:ProjectTaskPropertyMapping TaskProperty="ConstraintDate" 10: DataObjectProperty="ConstraintDate" /> 11: <ig:ProjectTaskPropertyMapping TaskProperty="DurationFormat" 12: DataObjectProperty="DurationFormat" /> 13: <ig:ProjectTaskPropertyMapping TaskProperty="Tasks" 14: DataObjectProperty="Tasks" /> 15: 16: 17: 18: 19: <ig:ProjectTaskPropertyMapping TaskProperty="IsManual" 20: DataObjectProperty="IsUndetermined" /> 21: 22: 23: 24: 25: 26: <ig:ProjectTaskPropertyMapping TaskProperty="Predecessors" DataObjectProperty="Predecessors" /> 27: 28: 29: 30: 31: 32: <ig:ProjectTaskPropertyMapping TaskProperty="IsActive" 33: DataObjectProperty="IsInProgress" /> 34: 35: 36: 37: 38: 39: <ig:ProjectTaskPropertyMapping TaskProperty="TaskName" 40: DataObjectProperty="TaskName" /> 41: 42: <ig:ProjectTaskPropertyMapping TaskProperty="Start" 43: DataObjectProperty="Start" /> 44: 45: 46: <ig:ProjectTaskPropertyMapping TaskProperty="Duration" 47: DataObjectProperty="Duration" /> 48: 49: 50: <ig:ProjectTaskPropertyMapping TaskProperty="IsMilestone" 51: DataObjectProperty="IsMilestone" /> 52: 53: <ig:ProjectTaskPropertyMapping TaskProperty="Deadline" 54: DataObjectProperty="DeadlineDate" /> 55: 56: 57: 58: 59: ig:ProjectTaskPropertyMappingCollection> 60: ig:ListBackedProject.TaskPropertyMappings> Binding to Data Using Project If you want to load a data from external source like a Microsoft Project 2010 XML file or you want to create an empty project and fill the tasks later, you may use the XamGantt Project property. In this scenario you can maintain data using XamGantt built-in classes and import/export projects using other formats. To be possible to use built-in project tasks you need to: Create an instance of the XamGantt Create an instance of Project Set the XamGantt Project property to the created Project instance Create a ViewModel with a property representing a Gantt Project 1: class NativeProjectViewModel : ObservableModel 2: { 3: #region Constructor 4: public NativeProjectViewModel() 5: { 6: this._project = new Project(); 7: ProjectTask root = new ProjectTask { TaskName = "Root Task", IsManual = false, Duration = new TimeSpan(3, 0, 0, 0) }; 8: 9: Project.RootTask.Tasks.Add(root); 10: } 11: #endregion //Constructor 12: 13: #region SelectedTask 14: private ProjectTask _selectedTask; 15: public ProjectTask SelectedTask 16: { 17: get 18: { 19: return _selectedTask; 20: } 21: set 22: { 23: if (value != null) 24: { 25: _selectedTask = value; 26: } 27: 28: NotifyPropertyChanged("SelectedTask"); 29: } 30: } 31: #endregion SelectedTask 32: 33: #region Project 34: private Project _project; 35: public Project Project 36: { 37: get 38: { 39: return this._project; 40: } 41: set 42: { 43: if (this._project != value) 44: { 45: this._project = value; 46: this.NotifyPropertyChanged("Project"); 47: } 48: } 49: } 50: #endregion //Project 51: 52: } Create an instance of Project 1: 2: "nativeviewmodel" /> 3: Set the XamGantt Project property to the created Project instance 1: "{StaticResource nativeviewmodel}"> 2: "10" x:Name="nativeGantt" ActiveCellChanged="nativeGantt_ActiveCellChanged" Project="{Binding Project}"/> 3: Create Task You can create a task programmatically or via XamGantt UI (Context menu) Create Tasks (Using ListBackedProject, Arbitrary Tasks Collection and Custom Tasks) The sample below demonstrates how to create a custom task and add it to Tasks collection of your ViewModel (using C#) 1: TaskModel newTask = new TaskModel(); 2: 3: newTask.DurationFormat = Infragistics.Controls.Schedules.ProjectDurationFormat.ElapsedDays; 4: newTask.Duration = new TimeSpan(8, 0, 0); 5: newTask.IsMilestone = false; 6: newTask.TaskName = "CustomTask"; 7: newTask.Start = DateTime.Now; 8: newTask.IsUndetermined = true; 9: 10: model.Tasks.Add(newTask); 11: model.SelectedTask = newTask; Create Tasks (Using Project and ProjectTask) The sample below demonstrates how to create a ProjectTask instance task and add it to RootTask.Tasks collection of your the Project instance (using C#) 1: ProjectTask newTask = new ProjectTask(); 2: 3: newTask.DurationFormat = Infragistics.Controls.Schedules.ProjectDurationFormat.ElapsedDays; 4: newTask.Duration = new TimeSpan(8, 0, 0); 5: newTask.IsMilestone = false; 6: IEnumerable existingTasks = null; 7: newTask.TaskName = "MyTask"; 8: newTask.Start = DateTime.Now; 9: 10: model.Project.RootTask.Tasks.Add(newTask); 11: model.SelectedTask = newTask; Create a task programmatically or via XamGantt UI (Context menu –> Insert Task) Maintain Tasks Links (Tasks Dependencies) The XamGantt control provides functionality for creating dependency links between tasks within a project and supports the link types available in Microsoft Project 2010. You can specify a lead and lag time of the dependency as well. You create tasks dependencies programmatically using collections of tasks’ predecessors and successors. Use the ProjectTask Predecessors and Successors properties to create a collection of ProjectTaskDependency objects. The Successors and Predecessors collections expose two overload methods of the Add method. The first one takes as parameters ProjectTask and ProjectTaskLinkType. The second one takes as parameters ProjectTask, ProjectTaskLinkType and ProjectDuration. Link type notation Link type Description FS Finish To Start If not otherwise specified this is the default link type. The successor's Start date is dependent upon the predecessor's Finish date. FF Finish To Finish The successor's Finish date is dependent upon the predecessor's Finish date. SF Start To Finish The successor's Finish date is dependent upon the predecessor's Start date. SS Start To Start The successor's Start date is dependent upon the predecessor's Start date. Create Links (Using ListBackedProject, Arbitrary Tasks Collection and Custom Tasks) To be possible to maintain task links using custom tasks you need to have at least one of these properties (Predecessors and Successors) or to have an appropriate custom properties that you can map to ProjectTask.Predecessors and/or ProjectTask.Successors. 1: #region Predecessors 2: private string _predecesors; 3: public string Predecessors 4: { 5: get { return _predecesors; } 6: set 7: { 8: if (value != _predecesors) 9: { 10: _predecesors = value; 11: this.NotifyPropertyChanged("Predecessors"); 12: } 13: } 14: } 15: #endregion //Predecessors 16: 17: #region Successors 18: private string _successors; 19: public string Successors 20: { 21: get { return _successors; } 22: set 23: { 24: if (value != _successors) 25: { 26: _successors = value; 27: this.NotifyPropertyChanged("Successors"); 28: } 29: } 30: } 31: #endregion //Successors You can maintain tasks dependencies also from XamGantt UI Create Links (Using Project and ProjectTask) Build-in ProjectTask class contains own Predecessors and Successors properties. You can use these properties in this case instead mapped properties of custom tasks. 1: ProjectTask task = new ProjectTask(); 2: task.DurationFormat = Infragistics.Controls.Schedules.ProjectDurationFormat.ElapsedDays; 3: task.ConstraintDate = new DateTime(2012, 10, 10, 8, 0, 0); 4: task.ConstraintType = ProjectTaskConstraintType.FinishNoLaterThan; 5: task.Duration = new TimeSpan(80, 0, 0); 6: 7: task.IsMilestone = false; 8: task.TaskName = "Sample task"; 9: task.TaskName = "Sample task" 10: task.Start = new DateTime(2012, 10, 2); 11: 12: model.Project.RootTask.Tasks.Add(task); 13: 14: ProjectTask lastTask = this.nativeGantt.Project.RootTask.Tasks.Last(); 15: 16: if (!task.Equals(lastTask)) 17: { 18: lastTask.Predecessors.Add(task, ProjectTaskLinkType.FinishToStart, ProjectDuration.FromFormatUnits(-2, ProjectDurationFormat.Days)); 19: 20: } Edit Task To edit tasks you can use Infragistics Gantt UI or to change tasks properties with code. Delete Task You can create a task programmatically with code or via XamGantt UI (Context menu) Delete Custom Task To delete custom tasks it is enough to remove the task from Arbitrary Tasks Collection 1: var model = this.Root.Resources["viewmodel"] as ProjectViewModel; 2: if (model != null) 3: { 4: DeleteCustomTask(model); 5: 6: } 7: 8: //Delete custom task 9: 10: private void DeleteCustomTask(ProjectViewModel model) 11: { 12: if (model.SelectedTask != null) 13: { 14: model.Tasks.Remove(model.SelectedTask); 15: model.SelectedTask = null; 16: } 17: } Delete Project Task To delete a built-in ProjectTask instance you need to remove the task from Project.RootTask.Tasks collection 1: var model = this.Root.Resources["nativeviewmodel"] as NativeProjectViewModel; 2: if (model != null) 3: { 4: DeleteNativeTask(model); 5: 6: } 7: 8: //Delete project task 9: 10: private void DeleteNativeTask(NativeProjectViewModel model) 11: { 12: if (model.SelectedTask != null && model.SelectedTask != model.Project.RootTask) 13: { 14: model.Project.RootTask.Tasks.Remove(model.SelectedTask); 15: model.SelectedTask = null; 16: } 17: } You can look at the sample application to see how to delete task in both cases Delete Task from XamGantt UI (Context menu –> Delete Task) Infragistics Gantt control is outright AWESOME! You can have almost everything from Microsoft Project, getting rid of all the useless stuff, and cramming it into a beautiful, lightweight, and high performance control that can be dragged into your WPF and Silverlight applications. Expect soon a new amazing Infragistics NetAdvantage Vol.12.2. Follow news from Infragistics for more information about new Infragistics products. Source code is available here. Sample project is created with Visual Studio 2012, but you can use NetAdvantage 12.2 controls with both: Visual Studio 2012 and Visual Studio 2012. As always, you can follow us on Twitter @mihailmateev and @Infragistics and stay in touch on Facebook, Google+ and LinkedIn!