Overview

13 partial files under Calendar/BeepCalendar.EventOperations.*.cs handle the complete event lifecycle plus the standalone CalendarEventEditor class. Every event mutation (add, update, delete) follows a three-phase pipeline: Pre-mutation (EventMutating with cancel support) → Execution (data change) → Post-mutation (EventMutated + history recording). An integrated undo/redo system records mutations on two stacks, and the conflict detection system checks scheduling overlap using configurable CalendarConflictPolicyMode.

Partial File Map (13 Files)

FileResponsibilityKey Members
EventOperations.csMutation raising + conflictRaiseMutating(), RaiseMutated(), GetConflicts(), CanApplyEventChange()
EventOperations.Public.csPublic API surfaceEvents: EventSelected, DateSelected, CreateEventRequested, ConflictDetected, EventMutating, EventMutated. Properties: EventEditor, CanUndo, CanRedo
EventOperations.Crud.csCRUD coordinator stubEmpty partial — dispatches to .Add / .Remove / .Upsert
EventOperations.Crud.Add.csAdd event logicAdds CalendarEvent, validates, fires mutation events
EventOperations.Crud.Remove.csRemove event logicRemoves by reference or ID, validates, fires mutations
EventOperations.Crud.Upsert.csUpsert event logicInsert-or-update — replaces if same ID exists
EventOperations.History.csUndo/Redo dispatcherUndoLastMutation(), RedoLastMutation()
EventOperations.History.Internal.csStack management_undoStack, _redoStack, push/pop logic
EventOperations.History.Apply.csReverse mutation applicationApplyMutationRecord(record, undo), reverse add=remove, reverse remove=add
EventOperations.Navigation.csDate navigationToday(), Next(), Previous()
EventOperations.Queries.csEvent queriesGetEventsForDate(), GetEventsForRange(), FindById()
EventOperations.Commands.csCommand executionCommand helpers + duplicate detection
EventOperations.Editor.csEditor integrationEditor.Commit.cs — commits edited event back to model

CRUD Operations

All event mutations follow a strict three-phase pipeline:

  1. Pre-mutation — RaiseMutating(kind, source, proposed, original, isNew, out canceled)
    • Fires EventMutating event with CalendarEventMutationEventArgs
    • Handlers may cancel by setting e.Cancel = true (validation, permissions, business rules)
  2. Execution — The actual data change: add to Events list, update properties, or remove from list
  3. Post-mutation — RaiseMutated(kind, source, result, original, isNew, conflicts)
    • Records mutation in undo/redo history with full state snapshot
    • Fires EventMutated event for UI refresh
    • Updates view button states (undo/redo enabled)

Mutation Pipeline

// Cancel a delete based on business rules
cal.EventMutating += (s, e) =>
{
    if (e.Kind == CalendarEventMutationKind.Delete
        && e.Original.Category == "Locked")
    {
        e.Cancel = true;  // Prevent deletion of locked events
    }
};

// React to completed mutations
cal.EventMutated += (s, e) =>
    Console.WriteLine($"{e.Kind}: {e.Result.Title}");

// Create event request
cal.CreateEventRequested += (s, e) =>
{
    e.CreatedEvent = CalendarEventEditor.ShowNewEventDialog(
        e.RequestedDate, e.RequestedStart);
};

Undo/Redo History

Two stacks manage the complete history:

  • _undoStack — Stack of mutation records, each containing the full before/after state of the event
  • _redoStack — Stack of undone mutations for redo capability
public bool UndoLastMutation()
{
    // Pop _undoStack, apply record in reverse, push to _redoStack
    // Returns false if stack is empty
}

public bool RedoLastMutation()
{
    // Pop _redoStack, reapply forward, push back to _undoStack
}

// Convenience API
if (cal.CanUndo) cal.Undo();
if (cal.CanRedo) cal.Redo();

History is implemented across 5 files: History.cs (dispatcher), History.Internal.cs (stack management), History.Apply.cs / Apply.Upsert.cs / Apply.Remove.cs (reverse mutation logic). Each mutation record stores the complete event state before and after the change.

Conflict Detection

// Three policy modes
cal.ConflictPolicyMode = CalendarConflictPolicyMode.Strict;
// None:   No conflict checking
// Warn:   Detect and fire ConflictDetected, but don't block
// Strict: Detect and block overlapping events

cal.ConflictDetected += (s, e) =>
{
    Console.WriteLine($"Conflict: {e.Description}");
    foreach (var conflict in e.ConflictingEvents)
        Console.WriteLine($"  {conflict.Title} ({conflict.Start}-{conflict.End})");
};

The conflict detection system uses a CalendarConflictPolicy object (lazy-created from _conflictPolicyMode) to check scheduling overlap before commit. Overlapping events are returned as CalendarConflictEventArgs.

CalendarEventEditor

Implements: ICalendarEventEditor | Visibility: public sealed

public sealed class CalendarEventEditor : ICalendarEventEditor
{
    public CalendarEventEditorMode Mode { get; set; }
    // QuickEdit:  compact 560x420 panel
    // DialogEdit: full 720x620 dialog

    public bool TryEdit(CalendarEventEditorRequest request,
        out CalendarEvent editedEvent);
    // Opens BeepDialogForm with CalendarEventEditorContent UserControl
    // Fields: Title TextBox, Start DateTimePicker, End DateTimePicker,
    //         AllDay CheckBox, Location TextBox, Status ComboBox
    // Advanced panel: Organizer TextBox, Description TextBox
}

CalendarEventEditorContent (internal sealed, extends UserControl) builds the editing UI with a TableLayoutPanel (4 rows, AutoScroll). Methods: LoadFromRequest() and BuildEditedEvent().

Categories & Resources

  • Categories — List<EventCategory>. Each category has Name, Color (for visual indicators), Icon path, and optional parent category for hierarchy. Events reference a category via CalendarEvent.Category.
  • Resources — List<CalendarResource> for room/equipment/person scheduling. Each resource has Name, Type, Capacity, Color, and optional Location.
  • PerformanceMetrics — CalendarPerformanceMetrics object (browsable=false) for tracking rendering time, interaction latency, and event operation timing.

Public Commands

5 command files expose the public command API: BeepCalendar.Commands.cs (main command definitions), Commands.Core.cs (execution engine), Commands.Helpers.cs (mutation context creation), Commands.DuplicateDetection.cs (dedup logic for command batching), Commands.MutationTracking.cs (mutation identity generation for auditing). Commands drive the public API indirectly — the calendar exposes user-facing methods that internally route through the command system for consistency.

Code Examples

Add Event with Validation

cal.EventMutating += (s, e) =>
{
    if (e.Proposed.End - e.Proposed.Start > TimeSpan.FromHours(8))
        e.Cancel = true;  // Reject events longer than 8 hours
};

cal.Events.Add(new CalendarEvent
{
    Title = "Design Review",
    Start = DateTime.Today.AddHours(10),
    End = DateTime.Today.AddHours(11),
    Location = "Room 204",
    Category = categories["Meeting"]
});

if (cal.CanUndo) cal.Undo();  // Revert if needed

Conflict Detection in Strict Mode

cal.ConflictPolicyMode = CalendarConflictPolicyMode.Strict;
cal.ConflictDetected += (s, e) =>
    MessageBox.Show($"Cannot schedule: {e.Description}");

cal.CreateEventRequested += (s, e) =>
{
    e.CreatedEvent = cal.EventEditor.TryEdit(
        new CalendarEventEditorRequest
        {
            ProposedDate = e.RequestedDate,
            Mode = CalendarEventEditorMode.QuickEdit
        }, out var result) ? result : null;
};