--- source_files: - Common/DTS.Common/Classes/UnityExtensions.cs - Common/DTS.Common/Classes/StatusAndProgressBarEventArgs.cs - Common/DTS.Common/Classes/Singleton.cs - Common/DTS.Common/Classes/BulkObservableCollection.cs - Common/DTS.Common/Classes/RegionNames.cs - Common/DTS.Common/Classes/ImportData.cs - Common/DTS.Common/Classes/ServiceCall.cs - Common/DTS.Common/Classes/TagAwareBase.cs - Common/DTS.Common/Classes/Utility.cs - Common/DTS.Common/Classes/Tags.cs generated_at: "2026-04-16T02:52:41.721329+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "b71265395aaf09cd" --- # DTS.Common Classes Documentation ## 1. Purpose This module provides foundational infrastructure utilities for the DTS application platform, focusing on dependency injection (via Unity), UI state management (status/progress), singleton pattern enforcement, high-performance collection operations, service orchestration, database-backed tagging system, and robust data access helpers. It serves as a shared library across the application to standardize common patterns, reduce boilerplate, and ensure thread-safe, consistent behavior for core operations like service queuing, tag management, and database interaction. ## 2. Public Interface ### `UnityExtensions` - **`T TryResolve(this IUnityContainer container) where T : class`** Safely resolves a service of type `T` from the Unity container, returning `null` instead of throwing on failure. ### `StatusAndProgressBarEventArgs` - **Properties** - `StatusColor`: `Color` – UI color for status indication. - `StatusText`: `string` – Human-readable status message. - `ProgressValue`: `double` – Numeric progress (e.g., 0.0–1.0 or 0–100). - `ProgressBarVisibility`: `Visibility` – Controls whether the progress bar is visible. - `Requester`: `IBaseViewModel` – Originator of the status update. - `ErrorText`: `string` – Optional error message to display. ### `Singleton` - **`protected Singleton()`** Constructor enforces singleton usage: throws `InvalidOperationException` if called directly (i.e., via `new T()` instead of `T.Instance`). - **`public static T Instance`** Gets the singleton instance. Throws the exception captured during static initialization if instance creation failed. ### `BulkObservableCollection` - **`void AddRange(IEnumerable items)`** Adds multiple items to the collection and fires a single `NotifyCollectionChangedAction.Reset` notification instead of per-item notifications. Logs exceptions via `APILogger`. - **`void RemoveRange(IEnumerable itemsToRemove)`** Removes multiple items and fires a single `Reset` notification. Logs exceptions via `APILogger`. ### `RegionNames` - **Constants** Static string constants defining Prism region names used for UI composition (e.g., `"FrontRegion"`, `"MainRegion"`, `"ViewerGraphMainRegion"`, `"MenuRegion"`). No methods. ### `ImportData` - **`enum ImportPageType`** - `ImportSensor`, `ImportTestSetup` - **`class SensorImportData`** Holds parsed sensor import data: - `GroupNameSensorListLookup`: `Dictionary>` - `SensorGroupNameLookup`, `SensorGroupTypeLookup`, `GroupNameTestObjectLookup`: `Dictionary` - `Errors`: `List` - `SensorISOCode`, `SensorISOChannelName`, `SensorUserCode`, `SensorUserChannelName`, `SensorDASSerialNumber`: `Dictionary` - `SensorChannelIndex`: `Dictionary` - **`class TestSetupImportData`** Holds parsed test setup import data: - `Name`, `Description`: `string` - `SamplesPerSecond`, `PosttriggerSeconds`, `PretriggerSeconds`: `double` - `RecordingMode`, `CalibrationBehavior`: Enum values - `Version`: `int` - `TestChannelOrders`, `Tags`: `List` - Clock configuration properties: `ClockMasterInput`, `ClockMasterOutput`, `ManageClocksOutsideOfDataPROMaster`, etc. - `SampleRateForDAS`, `DomainIdForDAS`, `IsClockMaster`: `Dictionary` ### `ServiceCall` - **`bool Started`** Indicates whether the call has been started. - **`Action WorkAction`** The work to execute. - **`void MarkDone()`** Signals completion by calling `ServiceQueue.MarkFinished(this)`. - **`string Name`** Human-readable identifier. - **`ServiceCall(string name)`** Constructor. ### `ServiceQueue` - **`static void Enqueue(ServiceCall call)`** Adds a `ServiceCall` to the queue. Starts execution immediately if queue was empty. - **`static void MarkFinished(ServiceCall call)`** Removes the call from the queue and starts the next queued call if any. Handles non-active calls (not at head) by simple removal. ### `TagAwareBase` - **`enum TagTypes`** `User`, `Group`, `Template`, `TestSetup`, `Sensors`, `SensorModels` - **`abstract TagTypes TagType { get; }`** Must be implemented by derived classes to specify tag type. - **`byte[] TagsBlobBytes`** Gets/sets `TagIDs` as a byte array (for DB storage). Logs exceptions on failure. - **`int[] TagIDs`** Gets/sets the list of tag IDs. - **`void SetTagsFromCommaSeparatedString(string tagText, Tags.GetSqlCommandDelegate getSqlCommand)`** Parses comma-separated tags and sets `TagIDs`. - **`virtual void SetTags(string[] tagsText, Tags.GetSqlCommandDelegate getSqlCommand)`** Adds tags to DB and updates `TagIDs`. Raises `OnPropertyChanged("TagIDs")`. - **`string GetTagsAsCommaSeparatedString(Tags.GetSqlCommandDelegate getSqlCommand)`** Returns tags as comma-separated string. - **`virtual string[] GetTagsArray(Tags.GetSqlCommandDelegate getSqlCommand)`** Returns tag text array. - **`virtual bool TagCompatible(string tags, ...)`** Checks if any tag in the provided comma-separated string matches current tags. - **`virtual bool TagCompatible(int[] tags)`** Checks if any tag ID in `tags` intersects with `TagIDs`. - **`virtual bool HasIntersectingTag(int[] tags)`** Returns `true` if `tags` and `TagIDs` share any ID. - **`void InsertTagsFromCommaSeparatedString(int id, TagTypes tagType, string tags, ...)`** Sets tags and commits assignments. - **`void Commit(int id, TagTypes tagType, ...)`** Deletes existing tag assignments for the object, then inserts new assignments for `TagIDs`. Uses stored procedures `sp_TagAssignmentsDelete` and `sp_TagAssignmentsInsert`. - **`List GetTagIdList(int objectId, TagTypes tagType, ...)`** Retrieves tag IDs for an object from DB via `sp_TagAssignmentsGet`. Logs failures. ### `Utility` - **`static byte[] GetBytesFromStringArray(string[] array, string separator)`** Joins array with `separator`, returns UTF-8 bytes. - **`static string GetAllErrorMessages(Exception ex)`** Recursively aggregates exception messages (including inner exceptions). - **`static bool PingNetwork(string hostNameOrAddress)`** Pings host with 4s timeout and fixed buffer. Returns `true` on success. - **`static T GetX(IDataReader reader, string column, T defaultValue = default)`** Generic pattern for safe column extraction: - `GetUShort`, `GetUInt`, `GetString`, `GetStringArray`, `GetInt`, `GetDouble`, `GetShort`, `GetNullableDateTime`, `GetUlong`, `GetNullableInt`, `GetByteArray`, `GetBool`, `GetDateTime`, `GetLong` All return `defaultValue` on `DBNull`, parse failure, or invalid column. Logs parse failures via `APILogger`. ### `Tags` - **`class Tag`** - `const int INVALID_ID = -1` - `int ID`, `string Text`, `bool IsObsolete` - Constructors: `(string, int)`, `(Tag)`, `(IDataRecord)`, `(DataRow)` - `object Clone()` → `new Tag(this)` - **`delegate SqlCommand GetSqlCommandDelegate(bool bNewConnection)`** Factory for database commands. - **`static Tags GetTagsInstance(GetSqlCommandDelegate getSqlCommand)`** Gets singleton instance (lazy-initialized). - **`static bool AddTag(string tagText, ...)`** Adds tag to DB if not present. Returns `true` if added. - **`static bool MigrateTag(string tagText, ...)`** Commits tag (used for DB migration). - **`static bool[] AddRange(string[] tagText, ...)`** Adds multiple tags. Trims leading whitespace before adding. - **`static int GetIDFromTagText(string tagText, ...)`** Gets tag ID from DB (returns `Tag.INVALID_ID` if not found). - **`static int[] GetIDsFromTagText(string[] tagText, ...)`** Gets tag IDs for array of texts. Filters out `INVALID_ID`. - **`static string GetTagTextFromID(int tagID, ...)`** Gets tag text from memory cache (returns `null` if invalid/missing). - **`static string[] GetTagTextFromIDs(int[] tagId, ...)`** Gets tag texts from IDs. Filters invalid/whitespace. - **`bool ContainsTag(string text)`** Checks if tag exists in memory cache. - **`void UpdateList(GetSqlCommandDelegate getSqlCommand)`** Refreshes memory cache from DB via `sp_TagsGet`. ## 3. Invariants - **Singleton**: - Only one instance per `T` exists. Attempting `new T()` throws `InvalidOperationException`. - Static constructor exceptions are captured and rethrown on `Instance` access. - **BulkObservableCollection**: - `AddRange`/`RemoveRange` fire exactly one `Reset` notification per call, regardless of item count. - `CheckReentrancy()` is called before modifications to prevent reentrancy issues. - **ServiceQueue**: - Only one `ServiceCall` executes at a time (via `Task.Run`). - Calls are processed in FIFO order. - `MarkFinished` only advances the queue if the finished call is the head of the queue. - **Tags**: - Tags are immutable (no rename/delete/obsolete support). - Memory cache (`_tagsLookup`) is lazily populated and updated only via `AddTag`, `MigrateTag`, or `UpdateList`. - `Tag.INVALID_ID` (`-1`) is used to indicate missing tags. - **TagAwareBase**: - `TagIDs` is never `null` (defaults to `new int[0]`). - `Commit` deletes existing assignments before inserting new ones. ## 4. Dependencies - **Imports/References**: - `Unity` (Microsoft Unity Container) - `System.Windows` (`Color`, `Visibility`) - `System.Data`, `System.Data.SqlClient` (ADO.NET) - `DTS.Common.Base` (`BasePropertyChanged`, `IBaseViewModel`) - `DTS.Common.Enums` (`RecordingModes`, `CalibrationBehaviors`, `InputClockSource`, `OutputClockSource`) - `DTS.Common.Interface.Sensors` (`ISensor`) - `DTS.Common.Utilities.Logging` (`APILogger`) - **Depended upon by**: - UI layers (via `RegionNames`, `StatusAndProgressBarEventArgs`) - Data import modules (`ImportData`) - Service orchestration consumers (`ServiceQueue`) - Tag-aware entities (`TagAwareBase`) - Database access layers (`Utility`, `Tags`) ## 5. Gotchas - **`Singleton`**: - Static initialization exceptions are logged to `Console.WriteLine` (not `APILogger`). - The singleton instance is created on first `Instance` access, not on module load. - **`BulkObservableCollection`**: - `AddRange`/`RemoveRange` use `NotifyCollectionChangedAction.Reset`, which may cause UI controls to re-render entirely (not incremental updates). - Exceptions in `AddRange`/`RemoveRange` are silently logged and do not propagate. - **`ServiceQueue`**: - `ServiceCall.Started` is used to prevent duplicate execution, but there is no cancellation mechanism. - Non-active calls (not at head) are removed from the queue without execution. - **`Tags`**: - Memory cache (`_tagsLookup`) is *not* automatically updated after `AddTag`/`MigrateTag` (only updated on `UpdateList` or explicit `Commit`). - `GetTagTextFromID` reads from cache only; if cache is stale, it may return `null` for valid IDs. - **`TagAwareBase`**: - `RemoveTags` is a stub (empty implementation). - `SetTagsFromCommaSeparatedString` does *not* skip empty strings (despite commented-out null check referencing FogBugz #7176). - **`Utility`**: - `PingNetwork` uses a fixed 32-byte buffer and 4-second timeout. - All `GetX` methods return `defaultValue` on parse failure without rethrowing. - **`ImportData.TestSetupImportData`**: - Clock master/slave properties (`ClockMasterInput`, `ClockMasterOutput`, etc.) default to `None` and `false`.