[Canonical page](<https://docs.dhtmlx.com/planning-engine/net/api/project-apply/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# Project.Apply

Writes edits into the accepted state of a [`Project`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/project.md>) and marks it unsolved. It doesn't schedule anything: follow it with [`Solve(null, …)`](<https://docs.dhtmlx.com/planning-engine/net/api/project-solve.md>) or [`Level`](<https://docs.dhtmlx.com/planning-engine/net/api/project-level.md>) to get the new dates.

## Signature

```csharp
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`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/project.md>).

## Parameters

| Name | Type | Description |
|---|---|---|
| `changes` | [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/scheduling-changes.md>) | The edits to commit |

## Behavior

- Operations are ordered and partially accepted. A rejected operation goes into [`ApplyReport.Rejected`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/apply-report.md#rejected>) and isn't thrown.
- Any rejection sets [`NeedsResync`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/apply-report.md#needsresync>). After that, [`Solve(null, …)`](<https://docs.dhtmlx.com/planning-engine/net/api/project-solve.md>), `Apply` and [`Level`](<https://docs.dhtmlx.com/planning-engine/net/api/project-level.md>) throw until a full `Solve(data, …)`.
- The state is unsolved afterwards, so [`Preview`](<https://docs.dhtmlx.com/planning-engine/net/api/project-preview.md>), [`LoadProfile`](<https://docs.dhtmlx.com/planning-engine/net/api/project-load-profile.md>), [`Evaluate`](<https://docs.dhtmlx.com/planning-engine/net/api/project-evaluate.md>), [`SuggestAssignments`](<https://docs.dhtmlx.com/planning-engine/net/api/project-suggest-assignments.md>) and [`Roster`](<https://docs.dhtmlx.com/planning-engine/net/api/project-roster.md>) need a solve first.
- The next acyclic `Solve(null, …)` or `Level` reports the tasks that successful operations added or updated.
- When `Apply` throws, nothing is applied and the project keeps its state.

## Returns

An [`ApplyReport`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/apply-report.md>) with the applied and rejected operations and their side effects.

## Errors

| Error | When |
|---|---|
| [`ProjectException`](<https://docs.dhtmlx.com/planning-engine/net/api/core/errors/project-exception.md>) 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.

```csharp
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`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/scheduling-changes.md>) - the edits to commit
- [`ApplyReport`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/apply-report.md>) - the returned report
- [`Project.Solve`](<https://docs.dhtmlx.com/planning-engine/net/api/project-solve.md>) - reschedules after the edits
- [Editing a project](<https://docs.dhtmlx.com/planning-engine/net/live-projects/editing-a-project.md>) - committing edits and rescheduling
- [Recover from rejected changes](<https://docs.dhtmlx.com/planning-engine/net/how-to/recover-from-rejected-changes.md>) - clearing `NeedsResync` after a rejected operation
