Project.Apply#
Writes edits into the accepted state of a Project and marks it unsolved. It doesn't schedule anything: follow it with Solve(null, …) or Level to get the new dates.
Signature#
public ApplyReport Apply(SchedulingChanges changes)
Synchronous and CPU-only. Changes the project's state, so don't call it while another thread uses the same Project.
Parameters#
| Name | Type | Description |
|---|---|---|
changes |
SchedulingChanges |
The edits to commit |
Behavior#
- Operations are ordered and partially accepted. A rejected operation goes into
ApplyReport.Rejectedand isn't thrown. - Any rejection sets
NeedsResync. After that,Solve(null, …),ApplyandLevelthrow until a fullSolve(data, …). - The state is unsolved afterwards, so
Preview,LoadProfile,Evaluate,SuggestAssignmentsandRosterneed a solve first. - The next acyclic
Solve(null, …)orLevelreports the tasks that successful operations added or updated. - When
Applythrows, nothing is applied and the project keeps its state.
Returns#
An ApplyReport with the applied and rejected operations and their side effects.
Errors#
| Error | When |
|---|---|
ProjectException with Code = ProjectError.NeedsResync |
An earlier Apply rejected an operation and no Solve(data, …) followed. Checked before changes.BaselineId, so it wins over StaleBaseline |
ProjectException with Code = ProjectError.StaleBaseline |
changes.BaselineId is set and doesn't name the current baseline. After an Apply with no solve since, the project has no baseline, so any non-null value fails |
ArgumentNullException |
changes is null |
Example#
Commit an edit, resync with full data when part of it is rejected, and reschedule.
using Plen;
var monday = Moment.FromYmdHm(2026, 8, 10, 8, 0) ?? throw new InvalidOperationException("invalid date");
var data = new ProjectData
{
Tasks = [new TaskData(1) { StartDate = monday, Duration = 2.0 }],
};
var project = new Project();
var solved = project.Solve(data, new SolveOptions());
var changes = new SchedulingChanges { BaselineId = solved.BaselineId };
changes.Tasks.Update.Add(new TaskUpdate(1) { Duration = 3.0 });
var report = project.Apply(changes);
foreach (var rejected in report.Rejected)
{
Console.WriteLine($"rejected at {rejected.Path}: {rejected.Message}");
}
var result = report.NeedsResync
? project.Solve(data, new SolveOptions())
: project.Solve(null, new SolveOptions());
Console.WriteLine($"{result.Updates.Count} task(s) moved");
Related#
SchedulingChanges- the edits to commitApplyReport- the returned reportProject.Solve- reschedules after the edits- Editing a project - committing edits and rescheduling
- Recover from rejected changes - clearing
NeedsResyncafter a rejected operation