Files
DP44/enriched-qwen3-coder-next/Common/DTS.Common/BusyIndicatorManager.md
2026-04-17 14:55:32 -04:00

90 lines
6.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
source_files:
- Common/DTS.Common/BusyIndicatorManager/xBusyIndicator.xaml.cs
- Common/DTS.Common/BusyIndicatorManager/BusyIndicatorManager.cs
generated_at: "2026-04-16T02:51:55.325916+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "abbbba42817259f5"
---
# BusyIndicatorManager
## Documentation: BusyIndicatorManager Module
---
### 1. Purpose
This module provides a centralized, singleton-based busy indicator management system for WPF applications using Prism. It coordinates multiple concurrent "busy sessions" (identified by integer IDs) and ensures the UI busy indicator reflects the aggregate state: if *any* session is active, the indicator is shown with the message from the *most recently added or updated* active session. It decouples business logic from UI presentation by exposing observable properties (`IsBusy`, `Message`) that can be bound to a `BusyIndicator` control (e.g., `Xceed.Wpf.Toolkit.BusyIndicator`), while allowing multiple components to request and release busy state independently without interfering with each other.
---
### 2. Public Interface
#### `BusyIndicatorManager` (Singleton Class)
- **`public static BusyIndicatorManager Instance { get; }`**
Thread-safe singleton accessor. Returns the single shared instance of `BusyIndicatorManager`. Uses double-checked locking via `SyncRoot`.
- **`public bool IsBusy { get; }`**
Read-only property indicating whether *any* busy session is currently active. Raises `PropertyChanged` on change (via `BindableBase`).
*Note:* Set only internally via `RaisePropertyChanged`.
- **`public string Message { get; }`**
Read-only property containing the message to display in the busy indicator. Reflects the message of the *last added/updated* active session (see `ShowBusy`/`CloseBusy` logic). Raises `PropertyChanged` on change.
- **`public void ShowBusy(int id, string busyMessage)`**
Registers or updates a busy session identified by `id`.
- If `id` is new: adds `(id, busyMessage)` to `busyParameters`, sets `IsBusy = true`, and sets `Message = busyMessage`.
- If `id` already exists: updates its message in `busyParameters`, sets `IsBusy = true`, and sets `Message = busyMessage` (i.e., *always* updates to the latest message for this session).
- **`public void CloseBusy(int id)`**
Removes the busy session identified by `id`.
- If `id` exists: removes it from `busyParameters`.
- After removal:
- If `busyParameters.Count == 0`: sets `IsBusy = false`, `Message = string.Empty`.
- Else: sets `IsBusy = true`, `Message = busyParameters.Last().Value` (i.e., message from the *last-enumerated* remaining session — *not necessarily the most recent*).
#### `xBusyIndicator` (Partial Class)
- **`public xBusyIndicator()`**
Constructor. Calls `InitializeComponent()` to load XAML resources.
- **`public void Connect(int connectionId, object target)`**
*Currently empty implementation.* No behavior defined in source. Purpose unclear without additional context.
---
### 3. Invariants
- **Session uniqueness**: Each `id` passed to `ShowBusy`/`CloseBusy` must be unique *per caller* to avoid unintended overwrites or conflicts. The manager does not enforce uniqueness across callers.
- **Message semantics**: `Message` always reflects the value of the *last entry* in the `busyParameters` dictionary (via `Last()`), which depends on dictionary enumeration order (insertion order in .NET 6+ for `Dictionary<TKey, TValue>`). This is *not* guaranteed to be the *most recently added* session if sessions are closed/reopened.
- **State consistency**: `IsBusy` is `true` iff `busyParameters.Count > 0`.
- **Thread safety**: Singleton instantiation is thread-safe via `lock(SyncRoot)`. However, *all other methods (`ShowBusy`, `CloseBusy`)* are **not thread-safe** — concurrent calls may corrupt `busyParameters` (e.g., race in `ContainsKey`/`Add`/`Remove`).
- **No cleanup on ID reuse**: Reusing an `id` after `CloseBusy(id)` will overwrite the previous sessions message (via `ShowBusy`), but no explicit cleanup of stale references occurs beyond the dictionary update.
---
### 4. Dependencies
#### Dependencies *of* this module:
- **Prism.Mvvm**: Used via `BindableBase` for property change notification (`RaisePropertyChanged`).
- **System.Collections.Generic**: For `Dictionary<int, string>`.
- **System.Linq**: For `Dictionary.Last()` in `CloseBusy`.
- **Xceed.Wpf.Toolkit**: Referenced via `BusyIndicator` usage (implied by `xBusyIndicator.xaml`), though not directly used in the C# code shown.
- **WPF**: `System.Windows.Controls` (likely for `BusyIndicator` control usage in XAML).
#### Dependencies *on* this module:
- Any UI component needing to show/hide a busy indicator must reference `DTS.Common.BusyIndicatorManager` and use `BusyIndicatorManager.Instance.ShowBusy(...)` / `CloseBusy(...)`.
- `xBusyIndicator.xaml` (WPF user control) likely binds to `BusyIndicatorManager.Instance.IsBusy` and `Message` (though binding logic is not in the provided source).
- *Inferred usage pattern*: Components call `ShowBusy(id, msg)` before long-running operations and `CloseBusy(id)` afterward (e.g., in `try/finally` blocks).
---
### 5. Gotchas
- **Non-deterministic message on partial close**: In `CloseBusy`, `Message` is set to `busyParameters.Last().Value`. Since `Dictionary<TKey, TValue>` enumeration order is insertion order (in modern .NET), this uses the *oldest remaining session*s message — *not* the most recently added one. This may cause confusing UI behavior if sessions overlap.
- **No ID validation**: `ShowBusy` and `CloseBusy` accept any `int id`. Negative or zero IDs are allowed but may cause conflicts if callers reuse IDs carelessly.
- **Thread-unsafety**: Methods `ShowBusy` and `CloseBusy` lack synchronization. Concurrent calls (e.g., from background threads) may cause `InvalidOperationException` (e.g., modifying collection during enumeration) or inconsistent state.
- **Empty `Connect` method**: The `xBusyIndicator.Connect` method has no implementation. Its purpose is unclear — possibly a placeholder for future binding logic or event wiring.
- **No timeout/cleanup mechanism**: Idle busy sessions (e.g., due to exceptions skipping `CloseBusy`) persist indefinitely until manually closed.
- **Message overwrites**: Calling `ShowBusy(id, msg)` for an existing `id` overwrites the message but does *not* reset the sessions position in the dictionary (so `Last()` may still refer to an older session).
*None identified from source alone.*
*Correction:* Several gotchas *are* apparent (see above).