Files

98 lines
8.0 KiB
Markdown
Raw Permalink Normal View History

2026-04-17 14:55:32 -04:00
---
source_files:
- Common/DTS.Common/Themes/CommonStyles.xaml.cs
- Common/DTS.Common/Themes/BrushesAndColors.cs
generated_at: "2026-04-16T02:56:39.284443+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "f6ea4f0f3bc31d60"
---
# Documentation: `DTS.Common` Theme Utilities
## 1. Purpose
This module provides shared WPF styling infrastructure for the DTS application suite, specifically offering two key capabilities: (1) centralized event handling for tooltip requests via `ToolTipEventHandler`, which routes help text requests through Prisms event aggregator, and (2) a static cache of pre-frozen WPF `Brush` and `Color` resources to avoid repeated resource lookups and improve rendering performance. It serves as a shared dependency for consistent UI theming across modules, decoupling resource consumption from XAML resource keys and reducing boilerplate in UI controls.
## 2. Public Interface
### `CommonStyles` (partial class)
- **`void ToolTipEventHandler(object sender, System.Windows.Controls.ToolTipEventArgs e)`**
Handles tooltip requests by marking the event as handled and publishing a `HelpTextEvent` (via `IEventAggregator`) with the original `sender` and `ToolTipEventArgs`. This enables centralized help-text provisioning for tooltip triggers.
### `BrushesAndColors` (abstract class)
All members are **static properties** returning cached `Brush` or `Color` instances. Each property corresponds to a specific resource key defined in external XAML (`brushes.xaml` or application resources). Properties are lazily initialized on first access.
#### Brush Properties (selected examples — full list below):
- **`Brush_ApplicationTileExport`** → `SolidColorBrush`
- **`Brush__ApplicationTileCollectData`** → `SolidColorBrush` *(note double underscore in name)*
- **`Brush_ApplicationStatus_Failed`**, **`Brush_ApplicationStatus_TSRAIRGo_Failed`** → `SolidColorBrush`
- **`Brush_Dimmed_Text`** → `SolidColorBrush`
- **`Brush_Application_Idle`**, **`Brush_ApplicationStatus_Idle`** → `SolidColorBrush` *(duplicate keys?)*
- **`Brush_ApplicationStatus_Busy`**, **`Brush_ApplicationStatus_TSRAIRGo_Busy`** → `SolidColorBrush`
- **`Brush_Run_SensorIdNotFound`**, **`Brush_Run_SensorIdOutOfPlace`** → `SolidColorBrush`
- **`Brush_Table_RowBackground`**, **`Brush_Table_AlternatingRowBackground`** → `SolidColorBrush`
- **`Brush_FlatControlPressedBackground`**, **`Brush_FlatControlPressedForeground`** → `Brush`
- **`Brush_Transparent`** → `Brush` (created internally as `new SolidColorBrush(Colors.Transparent)`)
- **`Brush_NoError`**, **`Brush_Error`**, **`Brush_Warning`**, **`Brush_Attention`** → `Brush`/`SolidColorBrush`
- **`Brush_FlatControlDisabledForeground`**, **`Brush_FlatControlDisabledBackground`** → `Brush`
- **`Brush_ApplicationStatus_Waiting`**, **`Brush_ApplicationStatus_Failed_ActionBackground`**, etc.
- **`Brush_Realtime_OSC_SELECTED`**, **`Brush_Realtime_OSC_UNSELECTED`**, **`Brush_Realtime_METER_SELECTED`**, **`Brush_Realtime_METER_UNSELECTED`** → `Brush`
- **`Brush_SensorIdFound`**, **`Brush_ArmSystemForeground`**, **`Brush_ApplicationTilePrepare`**, **`Brush_ApplicationTileSetup`** → `SolidColorBrush`
- **`BrushApplicationStatusPowerRed`**, **`BrushApplicationStatusPowerYellow`**, **`BrushApplicationStatusPowerGreen`**, **`BrushApplicationStatusPowerClear`** → `SolidColorBrush`
- **`BrushFlatControlDarkForeground`**, **`BrushButtonBorderForeground`** → `SolidColorBrush`
#### Color Properties (read-only, no caching):
- **`Color_ActionBackground`**, **`Color_ApplicationTileCollectData`**, **`Color_ItemBackground`**, **`Color_ActionForeground`**, **`Color_ItemForeground`**, **`Color_ApplicationTileSetup`**, **`Color_ApplicationTilePrepare`**, **`Color_ApplicationTileCalibration`**, **`Color_ApplicationTileExport`**, **`Color_ApplicationTileAdmin`**
`Color` (returned directly from `Application.Current.FindResource(...)` on each access; **not cached**)
> **Note**: The class is `abstract`, but no abstract members exist — likely a design artifact to prevent instantiation.
## 3. Invariants
- **Resource keys must exist at runtime**: All `FindResource` calls assume the resource key (e.g., `"Brush_ApplicationTileExport"`) is defined in `Application.Current.Resources` or in the merged dictionary `/DTS.Common;component/Themes/brushes.xaml`. Failure to define a key results in a `ResourceReferenceKeyNotFoundException`.
- **Brushes are frozen**: All `Brush`/`SolidColorBrush` instances are frozen (`Freeze()`) after retrieval to ensure thread-safety and immutability. Attempting to modify them will throw `InvalidOperationException`.
- **Lazy initialization with null-checks**: Each brush property uses a null-check pattern to ensure initialization occurs only once per app domain. However, some properties (e.g., `Brush_Warning`, `Brush_FlatControlDisabledForeground`) have inconsistent null-checking logic (see *Gotchas*).
- **No theme-switching support**: As noted in the class comment, the static caching means brushes may become stale if themes change at runtime (though the comment states themes are not currently used).
- **`Brush_Transparent` is internally constructed**: Unlike others, this brush is created via `new SolidColorBrush(Colors.Transparent)` rather than from a resource key.
## 4. Dependencies
### Dependencies *of* this module:
- **`DTS.Common.Events`** → Provides `HelpTextEvent` and `HelpTextEventArg`.
- **`Prism.Ioc`** and **`Prism.Events`** → Used for `ContainerLocator` and `IEventAggregator`.
- **`System.Windows`**, **`System.Windows.Media`** → WPF base types (`Brush`, `SolidColorBrush`, `Color`, `Application`, `ResourceDictionary`).
### Dependencies *on* this module:
- Any module requiring consistent UI styling (e.g., `DTS.DataPro`, UI projects) likely references `DTS.Common` and consumes `BrushesAndColors` properties directly.
- The `ToolTipEventHandler` is presumably wired to tooltip events in XAML (e.g., `ToolTipOpening="CommonStyles.ToolTipEventHandler"`), implying UI controls depend on this handler for help-text integration.
## 5. Gotchas
- **Inconsistent null-checking in `Brush_Warning`**:
The property `Brush_Warning` incorrectly assigns to `_brushError` instead of `_brushWarning` in its getter:
```csharp
_brushError = (SolidColorBrush)_resourceDictionary["Brush_Warning"]; // ❌ Should be _brushWarning
```
This causes `_brushWarning` to remain `null` indefinitely, leading to a `NullReferenceException` on first access.
- **Duplicate resource keys**:
`Brush_Application_Idle` and `Brush_ApplicationStatus_Idle` both resolve to `"Brush_ApplicationStatus_Idle"`. This redundancy suggests a naming inconsistency or refactoring artifact.
- **`Brush_FlatControlDisabledForeground` returns `null` silently**:
If the resource `"Brush_FlatControlDisabledForeground"` is missing, the property returns `null` (after `Freeze()` on `null` is a no-op). This may cause subtle rendering issues.
- **`BrushesAndColors` is `abstract` but not sealed**:
While no abstract members exist, the class could be `static` instead of `abstract` to enforce non-instantiability and prevent accidental subclassing.
- **Resource dictionary path is hardcoded**:
The `brushes.xaml` path (`/DTS.Common;component/Themes/brushes.xaml`) is embedded as a string. A typo or path change would break resource loading.
- **No thread-safety for first-time initialization**:
Although `Freeze()` is called, the lazy initialization (null-check + assignment) is not thread-safe. Concurrent first access could result in multiple instantiations (though freezing mitigates side effects).
- **Missing documentation for properties**:
No XML comments describe what each brush/color represents semantically (e.g., `Brush_ApplicationStatus_TSRAIRGo_Failed` vs `Brush_ApplicationStatus_Failed`), making maintenance difficult.
- **`Brush_ApplicationTileCollectData` has double underscore**:
`Brush__ApplicationTileCollectData` (two underscores) likely stems from a copy-paste or refactoring error (`Brush_ApplicationTileCollectData` would be consistent with others). This is a potential source of typos in consuming code.