Skip to content

Feature: View.GetScheme() should fall back gracefully instead of throwing when SchemeName is not found #4885

@YourRobotOverlord

Description

@YourRobotOverlord

Is your feature request related to a problem? Please describe.

When a View has SchemeName set to a custom scheme name and the active theme doesn't define that name, View.GetScheme() throws a KeyNotFoundException. This happens in common real-world situations:

  • A developer registers a custom scheme and sets SchemeName on their views, then the user switches to a built-in theme that doesn't include the custom scheme.
  • An end-user edits their config file and makes a typo in a scheme name.
  • An end-user deletes a custom scheme from their config, or upgrades to a version of the library where a scheme was renamed.
  • I found this to be an issue because I define several custom schemes for specific views - ListViews and ScrollBars are a prime example - and if I don't use a custom theme, my app crashes.

There is also an asymmetry: a view without SchemeName already falls back gracefully (SuperView → Base), but a view with SchemeName throws immediately if the name isn't found.

Reproduction:

SchemeManager.AddScheme("MyScheme", new Scheme { Normal = new Attribute(Color.Cyan, Color.Black) });
view.SchemeName = "MyScheme";

// Later — switch to a theme that doesn't define "MyScheme":
ThemeManager.Theme = "Dark";
ConfigurationManager.Apply();

view.GetScheme(); // KeyNotFoundException

This is also discussed in #4457.

Describe the solution you'd like

When SchemeName is set but the named scheme is not found in the active theme, View.GetScheme() should fall back gracefully through the following chain (consistent with how a view without SchemeName already behaves):

  1. Named scheme — if found in the active theme, use it
  2. SuperView.GetScheme() — inherit from the parent view (recursive)
  3. "Base" scheme from the active theme
  4. Hard-coded "Base" — always available regardless of config state

A warning should be written to the diagnostic log when a fallback occurs, so developers can detect misconfigured SchemeName values without a crash.

New API addition to SchemeManager:

// Non-throwing counterpart to GetScheme(string).
// Returns false if the scheme is missing or CM is not in a resolvable state.
public static bool TryGetScheme(string schemeName, [NotNullWhen(true)] out Scheme? scheme)

GetScheme(string) is left unchanged to preserve backward compatibility.

Describe alternatives you've considered

  • Throw with a better message — still crashes the app; not acceptable for a theme switch.
  • Return null from GetScheme() — would be a breaking API change and propagate null-handling throughout the codebase.
  • Validate SchemeName at assignment time — the scheme may not exist yet, or may be removed later; validation at set-time is the wrong layer.

Additional context

See discussion #4457 for the original proposal and proof-of-concept.

Metadata

Metadata

Assignees

No one assigned
    No fields configured for Feature.

    Projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions