Skip to content

Formalize the Cancellable Work Pattern as v2s core eventing model #3209

@dodexahedron

Description

@dodexahedron

The Cancellable Work Pattern is integral to Terminal.Gui, enabling flexible, decoupled workflows across scheme management, rendering, input, commands, and properties. Proposed helper classes streamline its implementation, particularly for property changes like Orientation. The Scheme system leverages the CWP for dynamic styling, while the Command system’s updates (Command.Activate, Handled, PropagatedCommands) enhance clarity and coordination. Ongoing documentation efforts ensure these improvements are well-communicated, supporting robust UI development in v2_develop.

This will be addressed in this PR:

Original Post

As mentioned in discussion #3206, event handling could use some TLC.

This issue is meant to be the main issue, though it may spawn others, depending on just how involved this ends up being.

Work items I wanted to address, many of which already have been partially completed in existing work on v2 or may not currently even exist/be problems in the current code, but I'm listing these out for completeness and as reminders for myself to at least confirm them all:

  • Standardize event delegates according to design recommendations
    • Basically, exactly how the Terminal.Gui design specification already says to do, but with an additional degree of scrutiny around the type arguments to EventHandler<T>, considering potential needs for future changes/features added to TG.
  • OnX wrappers for raising events are public, but most should be protected virtual and none should be public.
  • Declaring the actual events inside interfaces, which are then implemented by classes that need to expose those events.
  • Making sure that events are first defined at the most-derived type that is reasonable or necessary for common handling (the interfaces will help with that, too).
  • Ensure that, when relevant, derived classes ask their base class to raise the event, and that there are no virtual/overridden events nor any events hidden with new (I don't think either of those last things exist in the code)
  • Ensuring that standard rules and practices for inheritance and related concepts such as overrides are followed as closely as possible.
  • Consider and, if prudent, implement necessary constructs for thread-safety around event raising
    • Including at least being aware that subscribers may provide an async void handler that returns before the associated background work is actually complete. Though this doesn't necessarily mean actively attempting to defend against it, since that's 100% the consumer's fault.
  • Ensure/implement more formal/recommended handling of exceptions thrown in subsribers' handlers, as appropriate, via the following methods, as appropriate:
    • Stopping processing of the invocation list when an exception is caught and adding any relevant information to the stack trace before re-throwing the caught exception
    • Cleaning up or undoing any work the wrapper has done, if possible.
    • Cleaning up or undoing any work a handler has done, if it's safe to do so based on event or application state (this will probably be rare or not at all)
    • Hard-crashing the application immediately, via Environment.FailFast, if/when appropriate
    • Ensuring that raising of events (such as the wrappers themselves or the immediate call-sites of them) never throws exceptions, per design guidelines
    • Ensuring that exceptions thrown by handlers are not swallowed by the wrappers
      • If that behavior is desired and/or already exists anywhere, it will be modified to be an opt-in behavior, as that's a non-standard and counterindicated practice.

I think I'll start by getting an overall picture of all the events that exist and then work on creating appropriate interfaces that strike a balance between granularity and not needlessly creating tons of interfaces for no reason. Just as a guess based on what I know of TG, I'm betting there will probably be around 5ish interfaces, to group certain high-level categories of events common to types in specific hierarchies. But, we'll see. Could be more; Could be fewer.

Issues Potentially Impacted and/or Where Related Changes Are Needed

Metadata

Metadata

Assignees

Labels

designIssues regarding Terminal.Gui design (bugs, guidelines, debates, etc...)

Type

No type

Projects

Status

✅ Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions