TaskUpdate#

An edit to one existing task of a live project. It goes in the Update list of SchedulingChanges.Tasks, which Project.Apply and Project.Preview take. Create it with new TaskUpdate(id) and set the fields to change in an object initializer.

Declaration#

public sealed class TaskUpdate : IDeepCloneable<TaskUpdate>

Constructors#

TaskUpdate(Id)#

public TaskUpdate(Id id)

Creates an update for the task with the given id. Every other property is Patch<T>.Missing, so the update changes nothing until a property is set.

Name Type Description
id Id Id of the task to edit. A string, int or double converts implicitly.

Properties#

Every property except Id is a Patch<T>. Missing (the default) keeps the stored value, a value sets it, and Null clears it. The On Null column shows what Null leaves behind. For the meaning of each value, see the property of the same name on TaskData.

A plain value converts implicitly to a Patch<T>, so Duration = 3.0 works. An Id property needs Patch<Id>.Of(...) when the value is a string or a number, because C# doesn't chain the two implicit conversions.

Property Type On Null Description
Id Id required Id of the task to edit.
Parent Patch<Id> root level Moves the task under another parent. A value equal to SchedulingConfig.RootId is read as Null.
StartDate Patch<Moment> null New start, for example after a drag.
EndDate Patch<Moment> null New end.
Duration Patch<double> null New working time in the task's DurationUnit, for example after a resize.
ConstraintType Patch<ConstraintType> null New scheduling constraint.
ConstraintDate Patch<Moment> null New constraint date.
AutoScheduling Patch<bool> true false makes the task fixed.
Unscheduled Patch<bool> false true takes the task out of the plan.
Progress Patch<double> 0.0 New completed fraction.
CalendarId Patch<Id> null New working calendar.
Priority Patch<ushort> 500 New leveling priority.
LevelingDelay Patch<double> 0.0 New leveling delay, as elapsed time in the task's DurationUnit.
Pauses Patch<List<Pause>> empty Replaces the whole pause list. The task gets its own copy of the list.

Dates after an update#

An update starts from the task's current scheduled start, end and duration. On a leaf task (TaskType.Task), the properties set in the update decide which of the three is kept and which is derived again:

Set in the update Kept Derived again
StartDate, no EndDate start, duration end
EndDate only end, start duration
Duration, no EndDate start, duration end
StartDate + EndDate, no Duration start, end duration
CalendarId, or Parent under CalendarMode.TaskInherited, no date property start, duration end
Pauses or LevelingDelay, no date property start, duration end
  • A LevelingDelay update with neither StartDate nor EndDate also moves the stored dates by the change in delay (elapsed time) and snaps them onto working time.
  • When a task works on several calendars in a project with ScheduleFromEnd on, a Pauses or LevelingDelay update without dates keeps the end and derives the start instead.
  • Under CalendarMode.TaskInherited, a CalendarId or Parent update also re-derives the end of each descendant leaf task that has no CalendarId of its own. Its start and duration stay.
  • An explicit start on non-working time stays unsnapped when the task has no predecessor.

To write a result entry back as an update, see Mutation.

Methods#

DeepClone#

public TaskUpdate DeepClone()

Returns a copy that shares no list with this update, including the Pauses value.

Returns: a new TaskUpdate with the same values.

ToString#

public override string ToString()

Returns a debug dump of the fields, e.g. TaskUpdate { Id: a, Parent: Missing, StartDate: Missing, … }.

Errors#

An update is rejected as a single operation, at path tasks.update[i]. Project.Apply and Project.Preview describe how a rejection is reported.

Message When it occurs
unknown task id No task has Id.
a validation message The edited task breaks a TaskData rule or a ProjectData rule, for example an unknown CalendarId or Parent.

Example#

Move a task to a new start and make it one day longer:

using Plen;

var monday = Moment.FromYmdHm(2026, 4, 6, 8, 0) ?? throw new InvalidOperationException("invalid date");
var wednesday = Moment.FromYmdHm(2026, 4, 8, 8, 0) ?? throw new InvalidOperationException("invalid date");

var data = new ProjectData
{
    Tasks = [new TaskData("design") { StartDate = monday, Duration = 2.0 }],
};

var project = new Project();
project.Solve(data, new SolveOptions());

var changes = new SchedulingChanges();
changes.Tasks.Update.Add(new TaskUpdate("design") { StartDate = wednesday, Duration = 3.0 });

var report = project.Apply(changes);
if (report.Rejected.Count == 0)
{
    var result = project.Solve(null, new SolveOptions());
    foreach (var task in result.Updates)
    {
        Console.WriteLine($"{task.Id}: {task.StartDate} - {task.EndDate}");
    }
}