Version

Binding to Arbitrary Tasks Collection Using ListBackedProject

Topic Overview

Binding to Arbitrary Tasks Collection Using ListBackedProject

Introduction

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.

Provide a flat collection of custom tasks to the ListBackedProject, via its TaskItemsSource property and use the TaskPropertyMappings collection to define mappings between the custom task properties and the corresponding ProjectTask properties.

The following procedure illustrates populating a custom tasks collection from an XML file. This also results in the creation of a custom task Model and a ViewModel class that handles XML file operations.

Preview

The following screenshot previews the result.

Binding to Arbitrary Task Collection Using ListBackedProject 1.png

Prerequisites

To complete the procedure, you need the following:

  • A project with the following required NuGet package reference:

    • Infragistics.WPF.Gantt

    For more information on setting up the NuGet feed and adding NuGet packages, you can take a look at the following documentation: NuGet Feeds.

  • ListBackedProject

  • A project with the XElementExtension class containing extension methods for working with xml data

  • A sample xml data source - TaskData.xml

Steps

The following steps demonstrate how to bind a xamGantt control to a collection of custom tasks.

  1. Create a custom task Model class

    Create a custom task model that represents your data and implements the INotifyPropertyChanged interface.

    See the CodeCode Example: Custom Task Model for more details.

  2. Create a ViewModel class

    Create a ViewModel class that handles the xml data loading and has a public member Tasks of type ObservableCollection of TaskModel that stores the custom task’s data.

    See the CodeCode Example: ViewModel class for more details.

  3. Add the required namespaces in the XAML page

    Add the following namespaces at the beginning of the XAML page:

    In XAML:

    xmlns:ig="http://schemas.infragistics.com/xaml"
    xmlns:viewmodel="clr-namespace:<Your ViewModel Namespace>"
  4. Add a Grid in the page and bind its DataContext to the created ViewModel

    Add a Grid container in the page and bind the Grid DataContext property to the custom tasks view model class ListBackedProjectViewModel.

    In XAML:

    <Grid x:Name="LayoutRoot">
      <Grid.Resources>
        <viewmodel:ListBackedProjectViewModel x:Key="viewmodel"/>
      </Grid.Resources>
      <Grid.DataContext>
        <Binding Source="{StaticResource viewmodel}" />
      </Grid.DataContext>
    …
    </Grid>
  5. Create a ListBackedProject and bind it to data

    The ListBackedProject is a derived Project class that enables populating the tasks, based upon a provided flat collection of task information.

    The ListBackedProject is bound to the created custom tasks data stored in the Tasks public member via its TaskItemsSource property.

    In XAML:

    <ig:ListBackedProject x:Name="dataProvider"
                          TaskItemsSource="{Binding Tasks}">
    <!-- Add ProjectTask Property Mappings Here -->
    </ig:ListBackedProject>
  6. Create project task property to custom task property mappings

    Create a mappings collection using TaskPropertyMappings.

    In every ProjectTaskPropertyMapping, the TaskProperty specifies a ProjectTask property and the DataObjectProperty specifies the corresponding custom task property.

    For example, mapping the ProjectTask DataItemId property to the TaskID property defined in the custom TaskModel class.

    In XAML:

    <ig:ListBackedProject.TaskPropertyMappings>
      <ig:ProjectTaskPropertyMappingCollection
          UseDefaultMappings="True">
      <!--Start Mandatory Project Task Property Mappings-->
      <ig:ProjectTaskPropertyMapping
          TaskProperty="DataItemId"
          DataObjectProperty="TaskID" />
      <ig:ProjectTaskPropertyMapping
          TaskProperty="Tasks"
          DataObjectProperty="Tasks" />
      <ig:ProjectTaskPropertyMapping
          TaskProperty="ConstraintType"
          DataObjectProperty="ConstraintType" />
      <ig:ProjectTaskPropertyMapping
          TaskProperty="ConstraintDate"
          DataObjectProperty="ConstraintDate" />
      <ig:ProjectTaskPropertyMapping
          TaskProperty="DurationFormat"
          DataObjectProperty="DurationFormat" />
      <!--End Mandatory Project Task Property Mappings-->
      <!--Add the other Project Task Property Mappings-->
      </ig:ProjectTaskPropertyMappingCollection>
    </ig:ListBackedProject.TaskPropertyMappings>
    Note
    Note

    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.

    Note
    Note

    The following mappings are mandatory if you want to support task progress:

    • ActualStart and PercentComplete

    • or ActualStart and ActualDuration

    Note
    Note

    The following mappings are mandatory if you want to support manual tasks:

    • IsManual

    • Start

    • Duration

    • Finish

    Note
    Note

    The following mappings are mandatory if you want to create links between tasks:

    • Predecessors

    Note
    Note

    The following mappings are mandatory if you want to assign resources:

    • Resources

  7. Set the xamGantt Project property to the created ListBackedProject

    Set the xamGantt Project property to the existing ListBackedProject:

    In XAML:

    <ig:XamGantt x:Name="gantt"
        Project="{Binding ElementName=dataProvider}" />

Code Examples

Code examples summary

The following table lists the code examples included in this topic.

Example Description

The code example demonstrates a class that implements the INotifyPropertyChanged interface. Both the TaskModel and ListBackedProjectViewModel classes use this class to notify of properties changes.

The code example demonstrates a custom task Model and inherits the ObservableModel class.

The code example demonstrates a ViewModel class that handles the xml data loading and inherits the ObservableModel class.

The code example demonstrates creating of a ListBackedProject, adding and binding a xamGantt control to data.

Code Example: Observable Model

Description

This code example demonstrates a class that implements the INotifyPropertyChanged interface. Both the TaskModel and ListBackedProjectViewModel classes use this to notify the clients of properties changes.

Code

In C#:

public class ObservableModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

In Visual Basic:

Public Class ObservableModel
    Implements INotifyPropertyChanged
    Public Event PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
    Protected Overridable Sub NotifyPropertyChanged(ByVal propertyName As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub
End Class

Code Example: Custom Task Model

Description

The code example demonstrates a custom task Model that inherits the ObservableModel class.

You can add the Resources and sub-tasks as a comma separated string. For the sub-tasks, the comma separated string values that you enter need to match the properties that you map to the DataItemId property of the underlying ProjectTask for your ListBackedProject. The Predecessors also need to be added via comma separated string values.

Code

In C#:

using Infragistics.Controls.Schedules;
public class TaskModel : ObservableModel
{
    private string _taskId;
    public string TaskID
    {
        get
        {
            return _taskId;
        }
        set
        {
            if (_taskId != value)
            {
                _taskId = value;
                this.NotifyPropertyChanged("TaskID");
            }
        }
    }
    private string _tasks;
    public string Tasks
    {
        get
        {
            return _tasks;
        }
        set
        {
            if (_tasks != value)
            {
                _tasks = value;
                this.NotifyPropertyChanged("Tasks");
            }
        }
    }
    private string _name;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            if (_name != value)
            {
                _name = value;
                this.NotifyPropertyChanged("Name");
            }
        }
    }
    private ProjectTaskConstraintType _constraintType;
    public ProjectTaskConstraintType ConstraintType
    {
        get
        {
            return _constraintType;
        }
        set
        {
            if (_constraintType != value)
            {
                _constraintType = value;
                this.NotifyPropertyChanged("ConstraintType");
            }
        }
    }
    private DateTime? _constraintDate;
    public DateTime? ConstraintDate
    {
        get
        {
            return _constraintDate;
        }
        set
        {
            if (_constraintDate != value)
            {
                _constraintDate = value;
                this.NotifyPropertyChanged("ConstraintDate");
            }
        }
    }
    private ProjectDurationFormat _durationFormat;
    public ProjectDurationFormat DurationFormat
    {
        get
        {
            return _durationFormat;
        }
        set
        {
            if (_durationFormat != value)
            {
                _durationFormat = value;
                this.NotifyPropertyChanged("DurationFormat");
            }
        }
    }
    private TimeSpan _durationInHours;
    public TimeSpan DurationInHours
    {
        get
        {
            return _durationInHours;
        }
        set
        {
            if (_durationInHours != value)
            {
                _durationInHours = value;
                this.NotifyPropertyChanged("DurationInHours");
            }
        }
    }
    private DateTime _start;
    public DateTime Start
    {
        get
        {
            return _start;
        }
        set
        {
            if (_start != value)
            {
                _start = value;
                this.NotifyPropertyChanged("Start");
            }
        }
    }
    private bool _isMilestone = false;
    public bool IsMilestone
    {
        get
        {
            return _isMilestone;
        }
        set
        {
            if (_isMilestone != value)
            {
                _isMilestone = value;
                this.NotifyPropertyChanged("IsMilestone");
            }
        }
    }
    private bool _isInProgress = true;
    public bool IsInProgress
    {
        get
        {
            return _isInProgress;
        }
        set
        {
            if (_isInProgress != value)
            {
                _isInProgress = value;
                this.NotifyPropertyChanged("IsInProgress");
            }
        }
    }
    private DateTime? _deadlineDate;
    public DateTime? DeadlineDate
    {
        get
        {
            return _deadlineDate;
        }
        set
        {
            if (_deadlineDate != value)
            {
                _deadlineDate = value;
                this.NotifyPropertyChanged("DeadlineDate");
            }
        }
    }
    private bool _isUndetermined = false;
    public bool IsUndetermined
    {
        get
        {
            return _isUndetermined;
        }
        set
        {
            if (_isUndetermined != value)
            {
                _isUndetermined = value;
                this.NotifyPropertyChanged("IsUndetermined");
            }
        }
    }
    private string _resourceName;
    public string ResourceName
    {
        get
        {
            return _resourceName;
        }
        set
        {
            if (_resourceName != value)
            {
                _resourceName = value;
                this.NotifyPropertyChanged("ResourceName");
            }
        }
    }
}

In Visual Basic:

Imports Infragistics.Controls.Schedules
Public Class TaskModel
    Inherits ObservableModel
    Private _taskId As String
    Public Property TaskID() As String
        Get
            Return _taskId
        End Get
        Set(value As String)
            If _taskId <> value Then
                _taskId = value
                Me.NotifyPropertyChanged("TaskID")
            End If
        End Set
    End Property
    Private _tasks As String
    Public Property Tasks() As String
        Get
            Return _tasks
        End Get
        Set(value As String)
            If _tasks <> value Then
                _tasks = value
                Me.NotifyPropertyChanged("Tasks")
            End If
        End Set
    End Property
    Private _name As String
    Public Property Name() As String
        Get
            Return _name
        End Get
        Set(value As String)
            If _name <> value Then
                _name = value
                Me.NotifyPropertyChanged("Name")
            End If
        End Set
    End Property
    Private _constraintType As ProjectTaskConstraintType
    Public Property ConstraintType() As ProjectTaskConstraintType
        Get
            Return _constraintType
        End Get
        Set(value As ProjectTaskConstraintType)
            If _constraintType <> value Then
                _constraintType = value
                Me.NotifyPropertyChanged("ConstraintType")
            End If
        End Set
    End Property
    Private _constraintDate As System.Nullable(Of DateTime)
    Public Property ConstraintDate() As System.Nullable(Of DateTime)
        Get
            Return _constraintDate
        End Get
        Set(value As System.Nullable(Of DateTime))
            If _constraintDate <> value Then
                _constraintDate = value
                Me.NotifyPropertyChanged("ConstraintDate")
            End If
        End Set
    End Property
    Private _durationFormat As ProjectDurationFormat
    Public Property DurationFormat() As ProjectDurationFormat
        Get
            Return _durationFormat
        End Get
        Set(value As ProjectDurationFormat)
            If _durationFormat <> value Then
                _durationFormat = value
                Me.NotifyPropertyChanged("DurationFormat")
            End If
        End Set
    End Property
    Private _durationInHours As TimeSpan
    Public Property DurationInHours() As TimeSpan
        Get
            Return _durationInHours
        End Get
        Set(value As TimeSpan)
            If _durationInHours <> value Then
                _durationInHours = value
                Me.NotifyPropertyChanged("DurationInHours")
            End If
        End Set
    End Property
    Private _start As DateTime
    Public Property Start() As DateTime
        Get
            Return _start
        End Get
        Set(value As DateTime)
            If _start <> value Then
                _start = value
                Me.NotifyPropertyChanged("Start")
            End If
        End Set
    End Property
    Private _isMilestone As Boolean = False
    Public Property IsMilestone() As Boolean
        Get
            Return _isMilestone
        End Get
        Set(value As Boolean)
            If _isMilestone <> value Then
                _isMilestone = value
                Me.NotifyPropertyChanged("IsMilestone")
            End If
        End Set
    End Property
    Private _isInProgress As Boolean = True
    Public Property IsInProgress() As Boolean
        Get
            Return _isInProgress
        End Get
        Set(value As Boolean)
            If _isInProgress <> value Then
                _isInProgress = value
                Me.NotifyPropertyChanged("IsInProgress")
            End If
        End Set
    End Property
    Private _deadlineDate As System.Nullable(Of DateTime)
    Public Property DeadlineDate() As System.Nullable(Of DateTime)
        Get
            Return _deadlineDate
        End Get
        Set(value As System.Nullable(Of DateTime))
            If _deadlineDate <> value Then
                _deadlineDate = value
                Me.NotifyPropertyChanged("DeadlineDate")
            End If
        End Set
    End Property
    Private _isUndetermined As Boolean = False
    Public Property IsUndetermined() As Boolean
        Get
            Return _isUndetermined
        End Get
        Set(value As Boolean)
            If _isUndetermined <> value Then
                _isUndetermined = value
                Me.NotifyPropertyChanged("IsUndetermined")
            End If
        End Set
    End Property
    Private _resourceName As String
    Public Property ResourceName() As String
        Get
            Return _resourceName
        End Get
        Set(value As String)
            If _resourceName <> value Then
                _resourceName = value
                Me.NotifyPropertyChanged("ResourceName")
            End If
        End Set
    End Property
End Class

Code Example: ViewModel class

Description

The code example demonstrates a ViewModel class that handles xml data loading and inherits the ObservableModel class.

A public property Tasks of type ObservableCollection of TaskModel objects is created and populated with data from XML file. The code uses extension methods implemented in the XElementExtension class.

Code

In C#:

using Infragistics.Controls.Schedules;
public class ListBackedProjectViewModel : ObservableModel
{
    public ListBackedProjectViewModel()
    {
        this.DownloadDataSource();
    }
    private ObservableCollection<TaskModel> _tasks;
    public ObservableCollection<TaskModel> Tasks
    {
        get
        {
            return _tasks;
        }
        set
        {
            if (value != null)
            {
                _tasks = value;
            }
            NotifyPropertyChanged("Tasks");
        }
    }
    private void DownloadDataSource()
    {
        ObservableCollection<TaskModel> dataSource = new ObservableCollection<TaskModel>();
        XDocument xmlDoc = XDocument.Load("TaskData.xml");
        IEnumerable<XElement> elements = xmlDoc.Root.Elements();
        foreach (XElement el in elements)
        {
            TaskModel task = new TaskModel();
            task.TaskID = el.Element("TaskID").GetString();
            task.Name = el.Element("Name").GetString();
            task.IsInProgress = el.Element("IsInProgress").GetBool();
            task.Start = DateTime.Today.ToUniversalTime();
            task.IsMilestone = el.Element("IsMilestone").GetBool();
            task.DurationInHours = TimeSpan.FromHours(el.Element("DurationInHours").GetDouble());
            task.IsUndetermined = el.Element("IsUndetermined").GetBool();
            task.ResourceName = el.Element("ResourceName").GetString();
            task.DurationFormat = ProjectDurationFormat.Days;
            if (el.Element("DeadlineDateInHours").GetInt() != 0)
            {
                task.DeadlineDate = DateTime.Today.AddHours(el.Element("DeadlineDateInHours").GetInt()).ToUniversalTime();
            }
            dataSource.Add(task);
        }
        this._tasks = dataSource;
    }
}

In Visual Basic:

Imports Infragistics.Controls.Schedules
Public Class ListBackedProjectViewModel
    Inherits ObservableModel
    Public Sub New()
        Me.DownloadDataSource()
    End Sub
    Private _tasks As ObservableCollection(Of TaskModel)
    Public Property Tasks() As ObservableCollection(Of TaskModel)
        Get
            Return _tasks
        End Get
        Set(value As ObservableCollection(Of TaskModel))
            If value IsNot Nothing Then
                _tasks = value
            End If
            NotifyPropertyChanged("Tasks")
        End Set
    End Property
    Private Sub DownloadDataSource()
        Dim dataSource As New ObservableCollection(Of TaskModel)()
        Dim xmlDoc As XDocument = XDocument.Load("TaskData.xml")
        Dim elements As IEnumerable(Of XElement) = xmlDoc.Root.Elements()
        For Each el As XElement In elements
            Dim task As New TaskModel()
            task.TaskID = el.Element("TaskID").GetString()
            task.Name = el.Element("Name").GetString()
            task.IsInProgress = el.Element("IsInProgress").GetBool()
            task.Start = DateTime.Today.ToUniversalTime()
            task.IsMilestone = el.Element("IsMilestone").GetBool()
            task.DurationInHours = TimeSpan.FromHours(el.Element("DurationInHours").GetDouble())
            task.IsUndetermined = el.Element("IsUndetermined").GetBool()
            task.ResourceName = el.Element("ResourceName").GetString()
            task.DurationFormat = ProjectDurationFormat.Days
            If el.Element("DeadlineDateInHours").GetInt() <> 0 Then
                task.DeadlineDate = DateTime.Today.AddHours(el.Element("DeadlineDateInHours").GetInt()).ToUniversalTime()
            End If
            dataSource.Add(task)
        Next
        Me._tasks = dataSource
    End Sub
End Class

Code Example: Binding xamGantt to Custom Tasks Data in XAML via ListBackedProject

Description

The code example demonstrates creating a ListBackedProject, adding and binding a xamGantt control to data.

Code

In XAML:

Code
<Grid x:Name="LayoutRoot" Background="White">
  <Grid.Resources>
    <viewmodel:ListBackedProjectViewModel x:Key="viewmodel" />
  </Grid.Resources>
  <Grid.DataContext>
    <Binding Source="{StaticResource viewmodel}" />
  </Grid.DataContext>
  <ig:ListBackedProject x:Name="dataProvider"
                        TaskItemsSource="{Binding Tasks}">
    <ig:ListBackedProject.TaskPropertyMappings>
      <!-- Add Project Task Property Mappings Here -->
      <ig:ProjectTaskPropertyMappingCollection UseDefaultMappings="True">
        <!-- Start Mandatory Project Task Property Mappings -->
        <ig:ProjectTaskPropertyMapping TaskProperty="DataItemId"
                                       DataObjectProperty="TaskID" />
        <ig:ProjectTaskPropertyMapping TaskProperty="Tasks"
                                       DataObjectProperty="Tasks" />
        <ig:ProjectTaskPropertyMapping TaskProperty="ConstraintType"
                                       DataObjectProperty="ConstraintType" />
        <ig:ProjectTaskPropertyMapping TaskProperty="ConstraintDate"
                                       DataObjectProperty="ConstraintDate" />
        <ig:ProjectTaskPropertyMapping TaskProperty="DurationFormat"
                                       DataObjectProperty="DurationFormat" />
        <!-- End Mandatory Project Task Property Mappings -->
        <ig:ProjectTaskPropertyMapping TaskProperty="TaskName"
                                       DataObjectProperty="Name" />
        <ig:ProjectTaskPropertyMapping TaskProperty="Start"
                                       DataObjectProperty="Start" />
        <ig:ProjectTaskPropertyMapping TaskProperty="IsMilestone"
                                       DataObjectProperty="IsMilestone" />
        <ig:ProjectTaskPropertyMapping TaskProperty="IsActive"
                                       DataObjectProperty="IsInProgress" />
        <ig:ProjectTaskPropertyMapping TaskProperty="Duration"
                                       DataObjectProperty="DurationInHours" />
        <ig:ProjectTaskPropertyMapping TaskProperty="Deadline"
                                       DataObjectProperty="DeadlineDate" />
        <ig:ProjectTaskPropertyMapping TaskProperty="IsManual"
                                       DataObjectProperty="IsUndetermined" />
        <ig:ProjectTaskPropertyMapping TaskProperty="Resources"
                                       DataObjectProperty="ResourceName" />
      </ig:ProjectTaskPropertyMappingCollection>
    </ig:ListBackedProject.TaskPropertyMappings>
  </ig:ListBackedProject>
  <ig:XamGantt x:Name="gantt"
               Project="{Binding ElementName=dataProvider}"/>
</Grid>

The following topics provide additional information related to this topic.

Topic Purpose

This topic gives an overview of xamGantt control data binding.

This topic describes how the xamGantt control is bound to data via Project property.

This topic describes how an already created project plan saved in a Microsoft Project™ 2010 XML file is loaded in the xamGantt control.