GanttView for WPF
検証

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#
    コードのコピー
    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#
    コードのコピー
    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#
    コードのコピー
    private void OnListChanged(object? sender, System.ComponentModel.ListChangedEventArgs e)
    {
        foreach (Task task in gv.Tasks)
        {
            if (task.Initialized)
            {
                // 周期的なタスクを見つけます。
                var cyclicTasks = task.FindCyclicTasks();
    
                if (cyclicTasks.Any())
                {
                    // 周期的なタスクをクリアします。
                    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);
                }
            }
        }
    }