234 lines
12 KiB
Markdown
234 lines
12 KiB
Markdown
---
|
||
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<T>(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<T>`
|
||
- **`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<T>`
|
||
- **`void AddRange(IEnumerable<T> 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<T> 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<string, List<string>>`
|
||
- `SensorGroupNameLookup`, `SensorGroupTypeLookup`, `GroupNameTestObjectLookup`: `Dictionary<string, string>`
|
||
- `Errors`: `List<string>`
|
||
- `SensorISOCode`, `SensorISOChannelName`, `SensorUserCode`, `SensorUserChannelName`, `SensorDASSerialNumber`: `Dictionary<string, string>`
|
||
- `SensorChannelIndex`: `Dictionary<string, int>`
|
||
- **`class TestSetupImportData`**
|
||
Holds parsed test setup import data:
|
||
- `Name`, `Description`: `string`
|
||
- `SamplesPerSecond`, `PosttriggerSeconds`, `PretriggerSeconds`: `double`
|
||
- `RecordingMode`, `CalibrationBehavior`: Enum values
|
||
- `Version`: `int`
|
||
- `TestChannelOrders`, `Tags`: `List<string>`
|
||
- Clock configuration properties: `ClockMasterInput`, `ClockMasterOutput`, `ManageClocksOutsideOfDataPROMaster`, etc.
|
||
- `SampleRateForDAS`, `DomainIdForDAS`, `IsClockMaster`: `Dictionary<string, ...>`
|
||
|
||
### `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<int> 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<T>**:
|
||
- Only one instance per `T` exists. Attempting `new T()` throws `InvalidOperationException`.
|
||
- Static constructor exceptions are captured and rethrown on `Instance` access.
|
||
|
||
- **BulkObservableCollection<T>**:
|
||
- `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<T>`**:
|
||
- Static initialization exceptions are logged to `Console.WriteLine` (not `APILogger`).
|
||
- The singleton instance is created on first `Instance` access, not on module load.
|
||
|
||
- **`BulkObservableCollection<T>`**:
|
||
- `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`. |