GanttView for WPF | ComponentOne
In This Topic
    Validation
    In This Topic

    GanttView not only facilitates you to create project schedules, but also helps you in keeping your project data consistent. It does so by prohibiting invalid data entries or modifications to avoid conflicts. For instance, it prevents cyclic connection between tasks to avoid illogical task relationships. Here, a cyclic connection refers to a connection that occurs when the successor task and the predecessor task are the same for a given task.

    The following GIF shows how GanttView prohibits the user to create a cyclic connection between tasks.

    To avoid cyclic connection in GanttView, follow the given steps:

    1. Create a method, say FindCyclicTasks(), to find cyclic connections in GanttView. Here, we used the Intersect method to check if a task has same predecessor and successor.
      C#
      Copy Code
      public static class Extensions
      {
          public static IEnumerable<Task> FindCyclicTasks(this Task task)
          {
              return task.Predecessors.Select(x => x.PredecessorTask).Intersect(task.Successors);
          }
      }
      
    2. Create ListChanged event of the TaskCollection class and subscribe to it. This event gets fired when the task list changes at runtime.
      C#
      Copy Code
      gv.Tasks.ListChanged += OnListChanged;
      
    3. Add the following code to the ListChanged event handler. This code checks for any cyclic connection within the project's schedule and clears it.
      C#
      Copy Code
      private void OnListChanged(object? sender, System.ComponentModel.ListChangedEventArgs e)
      {
          foreach (Task task in gv.Tasks)
          {
              if (task.Initialized)
              {
                  // find cyclic tasks
                  var cyclicTasks = task.FindCyclicTasks();
      
                  if (cyclicTasks.Any())
                  {
                      // clear cylcic tasks
                      var predecessors = task.Predecessors.Join(cyclicTasks,
                          predecessor => predecessor.PredecessorTaskID, 
                          successor => successor.ID, (predecessor, successor) => predecessor).ToList();
      
                      foreach (var predecessor in predecessors)
                          task.Predecessors.Remove(predecessor);
                  }
              }
          }
      }