Data Exchange with Infragistics XamGantt Control - Using XML (Part 1)

[Infragistics] Mihail Mateev / Sunday, October 14, 2012

Infragistics NetAdvantage Vol.12.2 offers the amazing XamGantt control  for WPF and Silverlight

The Infragistics Gantt component is a WPF and Silverlight cross-platform control that provides Microsoft Project style Gantt functionality. The XamGantt utilizes a Project instance that contains the task, resource and calendar information for the schedule and has a built in scheduling engine supporting many of the features present in Microsoft Project 2010.

Perhaps one of the first things you want to learn about Infragistics Gantt Control is how to store your data. Anyone who works with software for planning and management would like his projects can be used many times after closing the application

There are many different approaches to store the data:

  • Serializing data locally in XML or binary format
  • Storing data in a database using:
    - Database connection (only for WPF)
    - WEB services
  • Import from and export to Microsoft Project
    -  Using data exchange through files (XML or MS Project format (*. mpp))

    - Interact with a Microsoft Project COM-based object model via Office Primary Interop Assemblies (PIA)

If you develop multiuser systems you will probably use a database to store your projects. In a small single-user systems logical solution for storing and sharing data is to serialize data in an appropriate format.

When you want your system to exchange data with Microsoft Project you will probably try to exchange data files in MS Project. Infragistics Gantt Control can read projects in MS Project XML format,  but for now it does not export data in this format.

Possible solution to export is to have own implementation of the export to MS Project format using the Project XML Data Interchange Schema Reference and mspdi_pj14.xsd schema included in the Project 2010 SDK download.

In this article we will examine the circumstances of the simplest solution: Serializing data locally in XML or binary format.

What you need to know in advance:

Sample application:

Sample application for this article is implemented as WPF Windows application. Most cases are also valid for Silverlight applications.

Let’s create a simple WPF application and add XamGantt control instance inside it. You can start with the sample from my previous post: “How to Start Using Infragistics XamGantt Control”.  Add buttons to call from UI import and export XamGantt project.

Export Gantt Project in XML

The standard approach:

XML Serialization is the process of saving class member data into an XML document which can be transmitted over the internet or saved to a text file. Deserialization is the reverse process – loading class member data from an XML document. Only public classes and public properties and fields can be serialized – methods and private members are not serialized and cannot be deserialized. Private classes cannot be serialized and will result in a compilation error.

If you try to serialize Infragistics.Controls.Schedules.Project class instance (built-in XamGantt project) you will have some issues because there are many non public members and for this version of XamGantt it is not predicted Gantt Project to be serialized out of the box. You can use the built-in XamGantt Project and place your data in another class with public members before to serialize it.

Let us focus on the case where you can have own model for the tasks and bind the Gantt control instance to custom task collection from your model using ListBackedProject. It is easy to create own model that can be easily serialized. If your application uses pre-built Project class instead  custom model for project data you need to create a own model  to serialize data.

The first thing I do is create an XMLSerializer (located in the System.Xml.Serialization namespace) that will serialize objects of type Movie. The XMLSerializer will serialize objects to a stream, so we'll have to create one of those next. In this case, you need to serialize it to a file, so let’s  create a TextWriter. Then you can simply call Serialize on the XMLSerializer passing in the stream (textWriter) and the object (project ViewModel). Lastly you need to close the TextWriter because you should always close opened files. That's it! Let's create a custom model for project and see how this is used.

The code below demonstrates how to serialize your ViewModel.

 1: private void SaveGanttProject(ProjectViewModel model)
 2: {
 3:     Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
 4:     dlg.FileName = "Document"; // Default file name
 5:     dlg.DefaultExt = ".xml"; // Default file extension
 6:     dlg.Filter = "XML documents (.xml)|*.xml"; // Filter files by extension
 7:  
 8:     Nullable<bool> result = dlg.ShowDialog();
 9:  
 10:     // Process save file dialog box results
 11:     if (result == true)
 12:     {
 13:         // Save document
 14:         string filename = dlg.FileName;
 15:         XmlSerializer serializer = new XmlSerializer(typeof(ProjectViewModel));
 16:         TextWriter textWriter = new StreamWriter(filename);
 17:         serializer.Serialize(textWriter, model);
 18:         textWriter.Close();
 19:     }
 20: }

 

As a result you will have an XML files with a structure, similar to that shown below

 1: <?xml version="1.0" encoding="utf-8"?>
 2: <ProjectViewModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 3:   <SelectedTask>
 4:     <ConstraintType>FinishNoLaterThanConstraintType>
 5:     <ConstraintDate>2012-10-10T08:00:00ConstraintDate>
 6:     <DeadlineDate xsi:nil="true" />
 7:     <DurationFormat>ElapsedDaysDurationFormat>
 8:     <Duration />
 9:     <IsMilestone>falseIsMilestone>
 10:     <IsInProgress>trueIsInProgress>
 11:     <IsUndetermined>trueIsUndetermined>
 12:     <Predecessors>Sample task323:FS-2 daysPredecessors>
 13:     <Start>2012-10-11T13:00:00ZStart>
 14:     <TaskID>Sample task70TaskID>
 15:     <TaskName>Sample task70TaskName>
 16:   SelectedTask>
 17:   <Tasks>
 18:     <TaskModel>
 19:       <ConstraintType>FinishNoLaterThanConstraintType>
 20:       <ConstraintDate>2012-10-10T08:00:00ConstraintDate>
 21:       <DeadlineDate xsi:nil="true" />
 22:       <DurationFormat>ElapsedDaysDurationFormat>
 23:       <Duration />
 24:       <IsMilestone>falseIsMilestone>
 25:       <IsInProgress>trueIsInProgress>
 26:       <IsUndetermined>trueIsUndetermined>
 27:       <Start>2012-10-11T05:00:00ZStart>
 28:       <TaskID>Sample task323TaskID>
 29:       <TaskName>Sample task323TaskName>
 30:     TaskModel>
 31:     <TaskModel>
 32:       <ConstraintType>FinishNoLaterThanConstraintType>
 33:       <ConstraintDate>2012-10-10T08:00:00ConstraintDate>
 34:       <DeadlineDate xsi:nil="true" />
 35:       <DurationFormat>ElapsedDaysDurationFormat>
 36:       <Duration />
 37:       <IsMilestone>falseIsMilestone>
 38:       <IsInProgress>trueIsInProgress>
 39:       <IsUndetermined>trueIsUndetermined>
 40:       <Predecessors>Sample task323:FS-2 daysPredecessors>
 41:       <Start>2012-10-11T13:00:00ZStart>
 42:       <TaskID>Sample task592TaskID>
 43:       <TaskName>Sample task592TaskName>
 44:     TaskModel>
 45:     <TaskModel>
 46:       <ConstraintType>FinishNoLaterThanConstraintType>
 47:       <ConstraintDate>2012-10-10T08:00:00ConstraintDate>
 48:       <DeadlineDate xsi:nil="true" />
 49:       <DurationFormat>ElapsedDaysDurationFormat>
 50:       <Duration />
 51:       <IsMilestone>falseIsMilestone>
 52:       <IsInProgress>trueIsInProgress>
 53:       <IsUndetermined>trueIsUndetermined>
 54:       <Predecessors>Sample task323:FS-2 daysPredecessors>
 55:       <Start>2012-10-11T13:00:00ZStart>
 56:       <TaskID>Sample task70TaskID>
 57:       <TaskName>Sample task70TaskName>
 58:     TaskModel>
 59:   Tasks>
 60: ProjectViewModel>

 

This structure doesn't contain all the information about your tasks necessary to re-Established Gantt project. Property Duration doesn't have a value. What is the reason for this loss of data?

 1: <TaskModel>
 2:       <ConstraintType>FinishNoLaterThanConstraintType>
 3:       <ConstraintDate>2012-10-10T08:00:00ConstraintDate>
 4:       <DeadlineDate xsi:nil="true" />
 5:       <DurationFormat>ElapsedDaysDurationFormat>
 6:       <Duration />
 7:       <IsMilestone>falseIsMilestone>
 8:       <IsInProgress>trueIsInProgress>
 9:       <IsUndetermined>trueIsUndetermined>
 10:       <Predecessors>Sample task323:FS-2 daysPredecessors>
 11:       <Start>2012-10-11T13:00:00ZStart>
 12:       <TaskID>Sample task592TaskID>
 13:       <TaskName>Sample task592TaskName>
 14:     TaskModel>

 

There is a simple answer: TimeSpam data type has issues to be serialized.

 1: [Serializable]
 2: public class TaskModel : ObservableModel
 3: {
 4:  
 5: //class members....
 6:  
 7: #region Duration
 8:  private TimeSpan _duration;
 9:  
 10:  
 11:  public TimeSpan Duration
 12:  {
 13:      get
 14:      {
 15:          return _duration;
 16:      }
 17:      set
 18:      {
 19:          if (_duration != value)
 20:          {
 21:              _duration = value;
 22:              this.NotifyPropertyChanged("Duration");
 23:          }
 24:      }
 25:  }
 26:  #endregion Duration
 27:  
 28: //class members....
 29:  
 30: }

 

One suggested approach was to ignore the TimeSpan for serialization, and instead serialize the result of TimeSpan.Ticks (and use new TimeSpan(ticks) for deserialization). An example of this follows:

TimeSpan XML serialization

 1: [Serializable]
 2: public class TaskModel : ObservableModel
 3: {
 4:  
 5: //class members...
 6:  
 7: #region Duration
 8: private TimeSpan _duration;
 9:  
 10: [XmlIgnore]
 11: public TimeSpan Duration
 12: {
 13:     get
 14:     {
 15:         return _duration;
 16:     }
 17:     set
 18:     {
 19:         if (_duration != value)
 20:         {
 21:             _duration = value;
 22:             this.NotifyPropertyChanged("Duration");
 23:         }
 24:     }
 25: }
 26: #endregion Duration
 27:  
 28: #region DurationTicks
 29:  
 30: // Pretend property for serialization
 31: [XmlElement("Duration")]
 32: public long DurationTicks
 33: {
 34:     get { return _duration.Ticks; }
 35:     set { _duration = new TimeSpan(value); }
 36: }
 37:  
 38: #endregion DurationTicks
 39:  
 40: //class members...
 41:  
 42: }

If you don't like the extra property, you could implement IXmlSerializable, but then you have to do everything.

The structure below is as a result of serialization using TimeSpan.Ticks. In this case you will have Duration data in your file

 1: <?xml version="1.0" encoding="utf-8"?>
 2: <ProjectViewModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 3:   <SelectedTask>
 4:     <ConstraintType>FinishNoLaterThanConstraintType>
 5:     <ConstraintDate>2012-10-10T08:00:00ConstraintDate>
 6:     <DeadlineDate xsi:nil="true" />
 7:     <DurationFormat>ElapsedDaysDurationFormat>
 8:     <Duration>2880000000000Duration>
 9:     <IsMilestone>falseIsMilestone>
 10:     <IsInProgress>trueIsInProgress>
 11:     <IsUndetermined>trueIsUndetermined>
 12:     <Predecessors>Sample task344:FS-2 daysPredecessors>
 13:     <Start>2012-10-11T13:00:00ZStart>
 14:     <End>0001-01-01T00:00:00End>
 15:     <TaskID>Sample task720TaskID>
 16:     <TaskName>Sample task720TaskName>
 17:   SelectedTask>
 18:   <Tasks>
 19:     <TaskModel>
 20:       <ConstraintType>FinishNoLaterThanConstraintType>
 21:       <ConstraintDate>2012-10-10T08:00:00ConstraintDate>
 22:       <DeadlineDate xsi:nil="true" />
 23:       <DurationFormat>ElapsedDaysDurationFormat>
 24:       <Duration>2880000000000Duration>
 25:       <IsMilestone>falseIsMilestone>
 26:       <IsInProgress>trueIsInProgress>
 27:       <IsUndetermined>trueIsUndetermined>
 28:       <Start>2012-10-11T05:00:00ZStart>
 29:       <End>0001-01-01T00:00:00End>
 30:       <TaskID>Sample task344TaskID>
 31:       <TaskName>Sample task344TaskName>
 32:     TaskModel>
 33:     <TaskModel>
 34:       <ConstraintType>FinishNoLaterThanConstraintType>
 35:       <ConstraintDate>2012-10-10T08:00:00ConstraintDate>
 36:       <DeadlineDate xsi:nil="true" />
 37:       <DurationFormat>ElapsedDaysDurationFormat>
 38:       <Duration>2880000000000Duration>
 39:       <IsMilestone>falseIsMilestone>
 40:       <IsInProgress>trueIsInProgress>
 41:       <IsUndetermined>trueIsUndetermined>
 42:       <Predecessors>Sample task344:FS-2 daysPredecessors>
 43:       <Start>2012-10-11T13:00:00ZStart>
 44:       <End>0001-01-01T00:00:00End>
 45:       <TaskID>Sample task254TaskID>
 46:       <TaskName>Sample task254TaskName>
 47:     TaskModel>
 48:     <TaskModel>
 49:       <ConstraintType>FinishNoLaterThanConstraintType>
 50:       <ConstraintDate>2012-10-10T08:00:00ConstraintDate>
 51:       <DeadlineDate xsi:nil="true" />
 52:       <DurationFormat>ElapsedDaysDurationFormat>
 53:       <Duration>2880000000000Duration>
 54:       <IsMilestone>falseIsMilestone>
 55:       <IsInProgress>trueIsInProgress>
 56:       <IsUndetermined>trueIsUndetermined>
 57:       <Predecessors>Sample task344:FS-2 daysPredecessors>
 58:       <Start>2012-10-11T13:00:00ZStart>
 59:       <End>0001-01-01T00:00:00End>
 60:       <TaskID>Sample task720TaskID>
 61:       <TaskName>Sample task720TaskName>
 62:     TaskModel>
 63:   Tasks>
 64: ProjectViewModel>

 

Import Gantt Project from XML

Let's create an XMLSerializer (located in the System.Xml.Serialization namespace) that will serialize objects of type Movie. The XMLSerializer will deserialize objects from a stream. In this case, you need to deserialize it from a file, so let’s  create a TextReader. Then you can call Deserialize on the XMLSerializer passing in the stream (textReader) and the object (project ViewModel). Lastly you need to close the TextWriter lbecause you should always close opened files. (Like when you serialize your project).

The code below demonstrates how to deserialize your ViewModel.

 1: #region ReadGanttProject
 2: private void ReadGanttProject(ref ProjectViewModel model)
 3: {
 4:     Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
 5:     dlg.FileName = "Document"; // Default file name
 6:     dlg.DefaultExt = ".xml"; // Default file extension
 7:     dlg.Filter = "XML documents (.xml)|*.xml"; // Filter files by extension
 8:  
 9:     Nullable<bool> result = dlg.ShowDialog();
 10:  
 11:     // Process save file dialog box results
 12:     if (result == true)
 13:     {
 14:         // Save document
 15:         string filename = dlg.FileName;
 16:  
 17:  
 18:         XmlSerializer deserializer = new XmlSerializer(typeof(ProjectViewModel));
 19:         TextReader textReader = new StreamReader(filename);
 20:         var newModel = (ProjectViewModel)deserializer.Deserialize(textReader);
 21:  
 22:         model.Tasks.Clear();
 23:  
 24:         foreach (TaskModel task in newModel.Tasks)
 25:         {
 26:  
 27:             model.Tasks.Add(task);
 28:             //Update PredecessorsIdText
 29:             xamGantt.Project.RootTask.Tasks.Last().PredecessorsIdText = task.PredecessorsIdText;
 30:         }
 31:  
 32:         textReader.Close();
 33:     }
 34: }
 35: #endregion ReadGanttProject

 

When you create a project from this XML file you will see tasks without links (task dependences).

The XamGantt control exposes the same constraint types as Microsoft Project 2010. To be possible to create task dependences you need to have correct information about links.

Write Task Dependences: 

To  create tasks dependencies programmatically you can use collections of tasks’ predecessors and successors. Use the ProjectTask Predecessors and Successors properties to create a collection of ProjectTaskDependency objects.

When you serialize predecessors or successors XMLSerializer will save data from available properties as a string. You will have data in format [Task Name]:[Task Dependences] - Sample task344:FS-2 days. To be possible to deserialize data correctly you need to implement own deserialization or to use a different  approach.

Default predecessors serialization

 1: <TaskModel>
 2:    <ConstraintType>FinishNoLaterThanConstraintType>
 3:    <ConstraintDate>2012-10-10T08:00:00ConstraintDate>
 4:    <DeadlineDate xsi:nil="true" />
 5:    <DurationFormat>ElapsedDaysDurationFormat>
 6:    <Duration>2880000000000Duration>
 7:    <IsMilestone>falseIsMilestone>
 8:    <IsInProgress>trueIsInProgress>
 9:    <IsUndetermined>trueIsUndetermined>
 10:    <Predecessors>Sample task344:FS-2 daysPredecessors>
 11:    <Start>2012-10-11T13:00:00ZStart>
 12:    <End>0001-01-01T00:00:00End>
 13:    <TaskID>Sample task254TaskID>
 14:    <TaskName>Sample task254TaskName>
 15:  TaskModel>
 16:  <TaskModel>

 

An alternative approach:

You can use PredecessorsIdText property instead Predecessors

 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

 

PredecessorsIdText is used to expose data from Predecessors as a string in format [TaskId][Task Dependences]  where TaskId is the index of the specified – not the value of TaskId property.

 1: #region PredecessorsIdText
 2: private string _predecessorsIdText;
 3: public string PredecessorsIdText
 4: {
 5:     get { return _predecessorsIdText; }
 6:     set
 7:     {
 8:         if (value != _predecessorsIdText)
 9:         {
 10:             _predecessorsIdText = value;
 11:             this.NotifyPropertyChanged("PredecessorsIdText");
 12:         }
 13:     }
 14: }
 15: #endregion //PredecessorsIdText

 

You can’t use in  ProjectTaskPropertyMappingCollection the ProjectTask.PredecessorsIdText property. You can use only Predecessors property.

 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:  
 40:                                
 41:  
 42:  
 43:                                <ig:ProjectTaskPropertyMapping TaskProperty="TaskName" 
 44:                                                   DataObjectProperty="TaskName" />
 45:  
 46:                                <ig:ProjectTaskPropertyMapping TaskProperty="Start" 
 47:                                                   DataObjectProperty="Start" />
 48:  
 49:  
 50:                                <ig:ProjectTaskPropertyMapping TaskProperty="Duration" 
 51:                                                   DataObjectProperty="Duration" />
 52:  
 53:  
 54:                                <ig:ProjectTaskPropertyMapping TaskProperty="IsMilestone" 
 55:                                                   DataObjectProperty="IsMilestone" />
 56:  
 57:                                <ig:ProjectTaskPropertyMapping TaskProperty="Deadline" 
 58:                                                   DataObjectProperty="DeadlineDate" />
 59:  
 60:                                
 61:  
 62:  
 63:                            ig:ProjectTaskPropertyMappingCollection>
 64:                        ig:ListBackedProject.TaskPropertyMappings>

 

You can add an additional logic before to serialize your project and get PredecessorsIdText property values for each custom task from the corresponding ProjectTask instances (built-in tasks in XamGantt control).

 1: #region UpdatePredecessorsIdText
 2: private void UpdatePredecessorsIdText(XamGantt gantt)
 3: {
 4:     foreach (ProjectTask task in gantt.Project.RootTask.Tasks)
 5:     {
 6:         var customTask = task.DataItem as TaskModel;
 7:         customTask.PredecessorsIdText = task.PredecessorsIdText;
 8:     }
 9: }
 10: #endregion UpdatePredecessorsIdText

 

Add a method that updates PredecessorsIdText property values before your code that serialize Gantt project.

 1: #region btnSave_Click
 2: private void btnSave_Click(object sender, RoutedEventArgs e)
 3: {
 4:     var tabIndex = this.ganttTabControl.SelectedIndex;
 5:  
 6:     if (tabIndex == 0)
 7:     {
 8:         var model = this.Root.Resources["viewmodel"] as ProjectViewModel;
 9:         if (model != null)
 10:         {
 11:             UpdatePredecessorsIdText(xamGantt);
 12:             SaveGanttProject(model);
 13:         }
 14:     }
 15:  
 16:     else if (tabIndex == 1)
 17:     {
 18:         var model = this.Root.Resources["nativeviewmodel"] as NativeProjectViewModel;
 19:         if (model != null)
 20:         {
 21:  
 22:             MessageBox.Show("XamGantt Project doesn't support XML serialization");
 23:         }
 24:     }
 25: }
 26: #endregion btnSave_Click

 

Now you will have information about the task dependences in your XML file.

 1: <?xml version="1.0" encoding="utf-8"?>
 2: <ProjectViewModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 3:   <Tasks>
 4:     <TaskModel>
 5:       <ConstraintType>StartNoEarlierThanConstraintType>
 6:       <ConstraintDate>2012-10-10T05:00:00ZConstraintDate>
 7:       <DeadlineDate xsi:nil="true" />
 8:       <DurationFormat>ElapsedDaysDurationFormat>
 9:       <Duration>2052000000000Duration>
 10:       <Index />
 11:       <IsMilestone>falseIsMilestone>
 12:       <IsInProgress>trueIsInProgress>
 13:       <IsUndetermined>trueIsUndetermined>
 14:       <Start>2012-10-10T05:00:00ZStart>
 15:       <End>0001-01-01T00:00:00End>
 16:       <TaskID>Sample task890TaskID>
 17:       <TaskName>Sample task890TaskName>
 18:     TaskModel>
 19:     <TaskModel>
 20:       <ConstraintType>StartNoEarlierThanConstraintType>
 21:       <ConstraintDate>2012-10-13T05:00:00ZConstraintDate>
 22:       <DeadlineDate xsi:nil="true" />
 23:       <DurationFormat>ElapsedDaysDurationFormat>
 24:       <Duration>2880000000000Duration>
 25:       <Index />
 26:       <IsMilestone>falseIsMilestone>
 27:       <IsInProgress>trueIsInProgress>
 28:       <IsUndetermined>trueIsUndetermined>
 29:       <Predecessors>Sample task890:FS-2 daysPredecessors>
 30:       <PredecessorsIdText>1FS-2 daysPredecessorsIdText>
 31:       <Start>2012-10-13T05:00:00ZStart>
 32:       <End>0001-01-01T00:00:00End>
 33:       <TaskID>Sample task655TaskID>
 34:       <TaskName>Sample task655TaskName>
 35:     TaskModel>
 36:     <TaskModel>
 37:       <ConstraintType>StartNoEarlierThanConstraintType>
 38:       <ConstraintDate>2012-10-13T05:00:00ZConstraintDate>
 39:       <DeadlineDate xsi:nil="true" />
 40:       <DurationFormat>ElapsedDaysDurationFormat>
 41:       <Duration>2880000000000Duration>
 42:       <Index />
 43:       <IsMilestone>falseIsMilestone>
 44:       <IsInProgress>trueIsInProgress>
 45:       <IsUndetermined>trueIsUndetermined>
 46:       <Predecessors>Sample task890:FS-2 daysPredecessors>
 47:       <PredecessorsIdText>1FS-2 daysPredecessorsIdText>
 48:       <Start>2012-10-13T05:00:00ZStart>
 49:       <End>0001-01-01T00:00:00End>
 50:       <TaskID>Sample task391TaskID>
 51:       <TaskName>Sample task391TaskName>
 52:     TaskModel>
 53:   Tasks>
 54: ProjectViewModel>

 

Custom task representation in XML file.

 1: <TaskModel>
 2:   <ConstraintType>StartNoEarlierThanConstraintType>
 3:   <ConstraintDate>2012-10-13T05:00:00ZConstraintDate>
 4:   <DeadlineDate xsi:nil="true" />
 5:   <DurationFormat>ElapsedDaysDurationFormat>
 6:   <Duration>2880000000000Duration>
 7:   <Index />
 8:   <IsMilestone>falseIsMilestone>
 9:   <IsInProgress>trueIsInProgress>
 10:   <IsUndetermined>trueIsUndetermined>
 11:   <Predecessors>Sample task890:FS-2 daysPredecessors>
 12:   <PredecessorsIdText>1FS-2 daysPredecessorsIdText>
 13:   <Start>2012-10-13T05:00:00ZStart>
 14:   <End>0001-01-01T00:00:00End>
 15:   <TaskID>Sample task655TaskID>
 16:   <TaskName>Sample task655TaskName>
 17: TaskModel>

 

Read Task Dependences

When you read your XML file you need to update your built-in project tasks in the same way like you update your custom model before to save it.

 1: #region ReadGanttProject
 2: private void ReadGanttProject(ref ProjectViewModel model)
 3: {
 4:     Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
 5:     dlg.FileName = "Document"; // Default file name
 6:     dlg.DefaultExt = ".xml"; // Default file extension
 7:     dlg.Filter = "XML documents (.xml)|*.xml"; // Filter files by extension
 8:  
 9:     Nullable<bool> result = dlg.ShowDialog();
 10:  
 11:     // Process save file dialog box results
 12:     if (result == true)
 13:     {
 14:         // Save document
 15:         string filename = dlg.FileName;
 16:  
 17:  
 18:         XmlSerializer deserializer = new XmlSerializer(typeof(ProjectViewModel));
 19:         TextReader textReader = new StreamReader(filename);
 20:         var newModel = (ProjectViewModel)deserializer.Deserialize(textReader);
 21:  
 22:         model.Tasks.Clear();
 23:  
 24:         foreach (TaskModel task in newModel.Tasks)
 25:         {
 26:  
 27:             model.Tasks.Add(task);
 28:             //Update PredecessorsIdText
 29:             xamGantt.Project.RootTask.Tasks.Last().PredecessorsIdText = task.PredecessorsIdText;
 30:         }
 31:  
 32:         textReader.Close();
 33:     }
 34: }
 35: #endregion ReadGanttProject

 

The code below shows how to call your method to deserialize model in the demo application.

 1: #region btnRead_Click
 2:  private void btnRead_Click(object sender, RoutedEventArgs e)
 3:  {
 4:      var tabIndex = this.ganttTabControl.SelectedIndex;
 5:  
 6:      if (tabIndex == 0)
 7:      {
 8:          var model = this.Root.Resources["viewmodel"] as ProjectViewModel;
 9:          if (model != null)
 10:          {
 11:              ReadGanttProject(ref model);
 12:          }
 13:      }
 14:  
 15:      else if (tabIndex == 1)
 16:      {
 17:          var model = this.Root.Resources["nativeviewmodel"] as NativeProjectViewModel;
 18:          if (model != null)
 19:          {
 20:  
 21:              MessageBox.Show("XamGantt Project doesn't support XML serialization");
 22:  
 23:          }
 24:      }
 25:  }
 26:  #endregion btnRead_Click

 

Enjoy! Now you have imported task dependences.

Conclusions

It is very easy to serialize your Gantt projects.  You should be careful about a few things:

  • Now to serialize task duration (TimeSpan is not serialized out of the box)
  • Now to serialize task dependences (Successors and Predecessors properties are not serialized correctly). In this case is better to use PredecessorsIdText property

Expect soon the next article in this series, in which you will learn how to exchange data between applications with Infragistics Gantt Control and Microsoft Project.

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!