--- source_files: - Common/DTS.CommonCore/BusyIndicatorManager/xBusyIndicator.xaml.cs - Common/DTS.CommonCore/BusyIndicatorManager/BusyIndicatorManager.cs generated_at: "2026-04-16T02:11:43.845066+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "85046dce961f12c2" --- # BusyIndicatorManager ## Documentation: BusyIndicatorManager Module --- ### 1. Purpose This module provides a centralized, singleton-based busy indicator management system for WPF applications, enabling multiple components or operations to request and release busy state independently while ensuring the UI reflects a consistent busy status. It decouples the *initiation* of busy operations (via unique IDs) from the *actual display* of the busy indicator, which is expected to be bound to the `IsBusy` and `Message` properties of the `BusyIndicatorManager` instance. The `xBusyIndicator` class serves as the XAML-backed UI control that presumably consumes this manager (though its current implementation is minimal). --- ### 2. Public Interface #### `BusyIndicatorManager` (Singleton) - **`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 request is currently active. Raises `PropertyChanged` on change (via `NotificationObject` base). - **`public string Message { get; }`** Read-only property containing the *current* busy message. Reflects the message of the *last added or active* busy request (see `ShowBusy`/`CloseBusy` behavior). Raises `PropertyChanged` on change. - **`public void ShowBusy(int id, string busyMessage)`** Registers a new busy request with the given `id`. If `id` is new, it adds the `busyMessage` to the internal dictionary and sets `IsBusy = true` and `Message = busyMessage`. If `id` already exists, it updates the stored message for that `id`, and ensures `IsBusy = true` and `Message = busyMessage` (i.e., overwrites current message regardless of prior state). *Note:* Does *not* deduplicate or prevent multiple `ShowBusy` calls with the same `id`—only updates the message. - **`public void CloseBusy(int id)`** Removes the busy request identified by `id`. If no requests remain (`busyParameters.Count == 0`), sets `IsBusy = false` and `Message = ""`. Otherwise, sets `IsBusy = true` and `Message = busyParameters.Last().Value` (i.e., the message of the *last-enumerated* remaining request). *Note:* Enumeration order of `Dictionary` is insertion order in .NET, but relying on `Last()` for priority is fragile and not guaranteed to be intuitive. #### `xBusyIndicator` (UI Control) - **`public xBusyIndicator()`** Constructor. Calls `InitializeComponent()` to load the XAML-defined UI. - **`public void Connect(int connectionId, object target)`** Currently **empty implementation**. Presumably intended to associate a UI element (`target`) with a logical connection ID (`connectionId`), but no behavior is defined in the source. --- ### 3. Invariants - **Singleton uniqueness**: Exactly one instance of `BusyIndicatorManager` exists per AppDomain (enforced via `lock` and null-check). - **`IsBusy` truthfulness**: - `IsBusy == true` **iff** `busyParameters.Count > 0`. - `IsBusy == false` **iff** `busyParameters.Count == 0`. - **`Message` consistency**: - When `IsBusy == true`, `Message` equals the `busyMessage` string associated with the *last-enumerated* entry in `busyParameters`. - When `IsBusy == false`, `Message == string.Empty`. - **ID uniqueness per request**: Each `id` in `ShowBusy(id, ...)` maps to one message in `busyParameters`. Reusing an `id` updates the message but does *not* create a new entry. --- ### 4. Dependencies #### Dependencies *of* this module: - **`Microsoft.Practices.Prism.ViewModel.NotificationObject`**: Base class for `BusyIndicatorManager`, enabling property change notifications (`RaisePropertyChanged`). - **`System.Collections.Generic`**: Used for `Dictionary`. - **`System.Linq`**: Used for `busyParameters.Last()` in `CloseBusy`. - **WPF UI framework**: `xBusyIndicator` inherits from `System.Windows.Controls.UserControl` (implied by `InitializeComponent()` and XAML usage). #### Dependencies *on* this module: - **UI components** (not visible in source): Presumably XAML views bind to `BusyIndicatorManager.Instance.IsBusy` and `.Message` to drive a `BusyIndicator` control (e.g., from `Xceed.Wpf.Toolkit`). - **`xBusyIndicator.xaml`**: The XAML file for `xBusyIndicator` (not provided), which likely consumes `BusyIndicatorManager` to display the busy state. --- ### 5. Gotchas - **`CloseBusy` message selection is arbitrary**: `busyParameters.Last()` uses dictionary enumeration order, which is insertion order in .NET, but this is not documented as a contract. If multiple requests are active, the displayed message may change unexpectedly when an unrelated request is closed. *Example:* Requests added in order `id=1`, `id=2`, `id=3` → closing `id=2` changes message to that of `id=3`, even if `id=1` was the "primary" request. - **No validation on `id`**: `ShowBusy` and `CloseBusy` accept any `int`. Duplicates are allowed (with update semantics), but no error is thrown for invalid IDs. - **`Connect` method is a stub**: `xBusyIndicator.Connect` has no implementation. Its purpose is unclear—without knowing the intended use of `connectionId` and `target`, this API is non-functional. - **No thread-safety for `busyParameters`**: While singleton instantiation is thread-safe, all operations on `busyParameters` (e.g., `ContainsKey`, `Add`, `Remove`, `Last`) are *not* synchronized. Concurrent calls to `ShowBusy`/`CloseBusy` from multiple threads may cause race conditions (e.g., `KeyNotFoundException`, corrupted dictionary state). *Note:* The singleton uses a lock for initialization only. - **Message overwriting on `id` reuse**: Calling `ShowBusy(42, "A")` then `ShowBusy(42, "B")` updates the message but does *not* reset `IsBusy` if it was already `true`. This may be intentional, but could mask bugs if callers assume each `ShowBusy` is independent. - **Hardcoded property names**: `RaisePropertyChanged("IsBusy")` uses string literals. No compile-time safety—renaming properties would break binding silently. - **No timeout or cancellation support**: Busy state persists indefinitely until `CloseBusy(id)` is called. No mechanism to auto-release or cancel long-running requests. - **`Xceed.Wpf.Toolkit` imported but unused**: The namespace is imported in `xBusyIndicator.xaml.cs`, but no `Xceed.Wpf.Toolkit` types are referenced in the provided code. May indicate future use or leftover artifact.