This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,141 @@
---
source_files:
- DataPRO/Modules/Hardware/AddEditHardware/Model/DASModule.cs
generated_at: "2026-04-16T04:37:06.260294+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "05acdd30203849a0"
---
# Model
## Documentation: `DASModule.cs`
---
### 1. **Purpose**
The `DASModule` class models a hardware module in a Data Acquisition System (DAS) for use in a WPF-based UI for adding or editing hardware configurations. It encapsulates module-specific metadata—including type, bridge configuration (for SLICE modules), serial number, and associated visual representation—and exposes this data through a property-changed-aware model suitable for data binding. It serves as a view-model-like abstraction for hardware modules in the `AddEditHardware` workflow, implementing `IAddEditHardwareDASModule` and inheriting from `BasePropertyChanged` to support UI updates via `INotifyPropertyChanged`.
---
### 2. **Public Interface**
#### `public bool Disabled { get; set; } = false;`
- Indicates whether this module instance is disabled (e.g., not in use). Default is `false`.
#### `public SLICEBridgeTypes SLICEBridgeType { get; set; }`
- Gets or sets the bridge type for SLICE modules (e.g., `Bridge`, `IEPE`, `ARS`, `ACC`).
- **Behavior**: On change, triggers `SetProperty`, then calls `SetImage()` to update the image based on the new type.
#### `public HardwareTypes ModuleType { get; set; }`
- Gets or sets the high-level hardware type (e.g., `SLICE_Bridge`, `TOM`, `SIM`, `DIM`, `UNDEFINED`).
- **Behavior**: On change, triggers `SetProperty`, then calls `SetImage()`.
#### `public string SerialNumber { get; set; }`
- Gets or sets the modules serial number (empty string by default). No validation or prefix enforcement is performed in this property.
#### `public ImageSource DASImage { get; set; }`
- Gets or sets the `ImageSource` used to display the modules image in the UI.
- **Behavior**: Set via `SetImage()` based on `ModuleType` and (for `SLICE_Bridge`) `SLICEBridgeType`. May be `null` if image loading fails or no matching asset is found.
#### `public SLICEBridgeTypes[] AvailableNanoBridges { get; }`
- Returns a read-only array of valid `SLICEBridgeTypes` for *nano*-form-factor SLICE modules:
`SLICEBridgeTypes.Bridge`, `SLICEBridgeTypes.IEPE`.
#### `public SLICEBridgeTypes[] AvailableMicroBridges { get; }`
- Returns a read-only array of valid `SLICEBridgeTypes` for *micro*-form-factor SLICE modules:
`SLICEBridgeTypes.Bridge`, `SLICEBridgeTypes.IEPE`, `SLICEBridgeTypes.ARS`, `SLICEBridgeTypes.ACC`.
#### `public HardwareTypes[] AvailableRACKModules { get; }`
- Returns a read-only array of valid hardware types for rack-mounted modules:
`HardwareTypes.UNDEFINED`, `HardwareTypes.SIM`, `HardwareTypes.TOM`, `HardwareTypes.DIM`.
#### `public IAddEditHardwareHardware OwningHardware { get; set; }`
- Reference to the parent hardware object (e.g., chassis or device) that owns this module. Used for contextual navigation or validation.
#### `public string GetSerialNumberPrefix()`
- Returns a short string prefix used for generating or validating serial numbers based on module type:
- `"DIM"` for `HardwareTypes.DIM`
- `"SIM"` for `HardwareTypes.SIM`
- `"TOM"` for `HardwareTypes.TOM`
- For `HardwareTypes.SLICE_Bridge`, returns a 2-letter prefix based on `SLICEBridgeType`:
- `"AC"` for `ACC`
- `"AR"` for `ARS`
- `"BR"` for `Bridge`
- `"IEPE"` for `IEPE`
- Returns `string.Empty` for `UNDEFINED` or unrecognized types.
#### `public DASModule()`
- Default constructor. Initializes `Disabled = false`, `_sliceBridgeType = Bridge`, `_moduleType = UNDEFINED`.
---
### 3. **Invariants**
- **Image Consistency**: `DASImage` is always derived from `ModuleType` and (if applicable) `SLICEBridgeType`. Changing either triggers `SetImage()` and updates `DASImage`.
- **Image Source URI**: All image paths are relative to the pack URI `pack://application:,,,/ResourceFile.xaml`.
- **Image Loading Failure Handling**: If image loading fails (e.g., missing file), `DASImage` is set to `null`, and an error is logged via `APILogger`.
- **Image Freezing**: Loaded `BitmapImage` instances are frozen for thread-safety and performance.
- **Module Type Constraints**:
- `SLICEBridgeType` is only meaningful when `ModuleType == HardwareTypes.SLICE_Bridge`.
- `AvailableNanoBridges` and `AvailableMicroBridges` are static and immutable; they define allowed values but are not enforced by property setters.
- **Serial Number Prefix**:
- `GetSerialNumberPrefix()` returns `string.Empty` for unrecognized or `UNDEFINED` module types.
---
### 4. **Dependencies**
#### **Imports/Usings**
- `System`, `System.Windows`, `System.Windows.Input`, `System.Windows.Media`, `System.Windows.Media.Imaging`
- `DTS.Common.Base``BasePropertyChanged`
- `DTS.Common.Enums.Hardware``SLICEBridgeTypes`, `HardwareTypes`
- `DTS.Common.Interface.Hardware.AddEditHardware``IAddEditHardwareDASModule`, `IAddEditHardwareHardware`
- `DTS.Common.Utilities.Logging``APILogger`
#### **External Dependencies**
- **WPF**: Uses `ImageSource`, `BitmapImage`, `Uri`, `pack://` URIs.
- **Common Libraries**:
- `DTS.Common.Base` for `BasePropertyChanged` (likely implements `INotifyPropertyChanged`).
- `DTS.Common.Enums.Hardware` for type definitions.
- `DTS.Common.Interface.Hardware.AddEditHardware` for interface contracts.
- `DTS.Common.Utilities.Logging` for error logging.
#### **Consumers**
- UI components bound to `DASModule` (e.g., `DataGrid`, `UserControl`) for editing hardware configurations.
- Any class implementing or consuming `IAddEditHardwareDASModule`.
- Likely instantiated and managed by a parent `IAddEditHardwareHardware` (via `OwningHardware`).
---
### 5. **Gotchas**
- **No Validation on `ModuleType`/`SLICEBridgeType` Combinations**:
The class allows setting `ModuleType = SLICE_Bridge` and `SLICEBridgeType = ACC`, but also allows `ModuleType = TOM` with `SLICEBridgeType = IEPE`, which is semantically invalid. Validation (if any) must occur elsewhere (e.g., in UI or service layer).
- **`Disabled` Property Has No Side Effects**:
Setting `Disabled = true` does not affect image loading, serial number generation, or any other logic in this class.
- **Image Paths Are Hardcoded and Fragile**:
`SetImage()` uses hardcoded relative paths (e.g., `@"Assets/Hardware/SLICEIEPE_Side.png"`). If assets are renamed or moved, image loading silently fails (logs error, sets `DASImage = null`).
- **`GetSerialNumberPrefix()` Returns `"IEPE"` (4 chars) While Others Are 23 chars**:
Inconsistent prefix length may cause downstream parsing issues if consumers assume fixed-width prefixes.
- **No Null/Empty Handling for `SerialNumber`**:
The property accepts any string, including `null` or whitespace. No validation or trimming is applied.
- **`OwningHardware` Is Not Initialized**:
The property is nullable and must be set externally; no constructor overloads or defaults are provided.
- **`_baseUri` Is Static and Fixed**:
Assumes all images are in the same resource file (`ResourceFile.xaml`). Not configurable at runtime.
- **Exception Handling in `SetImage()` Is Broad**:
Catches all exceptions during image loading but logs only the message (no stack trace or context), making debugging harder.
- **No Explicit Interface Implementation**:
The class implements `IAddEditHardwareDASModule` implicitly; if the interface defines additional members, they are not visible in this file.
- **None identified from source alone.** *(Note: The above are inferred from observed behavior, not documented quirks.)*

View File

@@ -0,0 +1,60 @@
---
source_files:
- DataPRO/Modules/Hardware/AddEditHardware/Properties/Settings.Designer.cs
- DataPRO/Modules/Hardware/AddEditHardware/Properties/AssemblyInfo.cs
generated_at: "2026-04-16T04:36:44.098121+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "2868c6abccf6511a"
---
# Properties
## Documentation: `AddEditHardware.Properties.Settings`
---
### 1. **Purpose**
This module defines the strongly-typed application settings class `AddEditHardware.Properties.Settings`, which inherits from `System.Configuration.ApplicationSettingsBase`. It serves as the programmatic interface for accessing user- or application-scoped configuration values for the `AddEditHardware` module. The class is auto-generated by Visual Studios settings designer and provides a singleton-style static accessor (`Default`) for retrieving settings at runtime. It does not contain any custom settings properties in the provided source—only the infrastructure to host them.
---
### 2. **Public Interface**
- **`Settings Default`** *(static property)*
- **Signature**: `internal static Settings Default { get; }`
- **Behavior**: Returns the singleton instance of the `Settings` class, synchronized for thread safety via `ApplicationSettingsBase.Synchronized()`. This is the sole public member exposed in the current source. No custom settings properties are defined here—any actual settings (e.g., `HardwareId`, `LastUsedTemplate`) would appear in the designer-generated body but are absent in the provided snippet.
> **Note**: The class is `internal sealed partial`, and the `Settings` type itself is `internal`. No public constructors or instance members are present.
---
### 3. **Invariants**
- The `defaultInstance` field is initialized once and reused for all accesses to `Default`.
- Thread safety is ensured by wrapping the initial `Settings` instance with `ApplicationSettingsBase.Synchronized()`, which enforces that all access to the settings instance is synchronized on a shared lock.
- The class is sealed and non-extensible in this file (though `partial` allows extension in other generated files, not shown here).
- No validation or custom logic is present in the provided source—behavior relies entirely on `ApplicationSettingsBase`.
---
### 4. **Dependencies**
- **Depends on**:
- `System.Configuration` (specifically `ApplicationSettingsBase`)
- `System.Runtime.CompilerServices.CompilerGeneratedAttribute`
- `System.CodeDom.Compiler.GeneratedCodeAttribute`
- **Depended on by**:
- Other modules in the `AddEditHardware` assembly (e.g., UI forms or services in `DataPRO/Modules/Hardware/AddEditHardware`) that consume settings via `Settings.Default`.
- The Visual Studio Settings Designer (at design time), which regenerates this file when settings are modified in the `.settings` designer file (not included here).
---
### 5. **Gotchas**
- **Auto-generated file**: This file is auto-generated by Visual Studio. Manual edits will be overwritten on rebuild or settings modification.
- **No settings defined in source**: The provided snippet contains *only* the base infrastructure—no actual settings properties (e.g., `public string SomeSetting { get; set; }`) are visible. Developers must check the corresponding `.settings` designer file (e.g., `Properties/Settings.settings`) to see configured values.
- **Internal visibility**: The `Settings` class and its `Default` property are `internal`, meaning they are only accessible within the `AddEditHardware` assembly. External consumers (e.g., other modules) must reference this assembly and access it via `AddEditHardware.Properties.Settings.Default`.
- **Thread-safety overhead**: The use of `Synchronized()` implies a performance cost for every access; if settings are read frequently, consider caching locally.
- **Versioning**: Assembly version is fixed at `1.0.0.0` (both `AssemblyVersion` and `AssemblyFileVersion`), which may impact upgrade behavior for user-scoped settings (e.g., migration logic in `Settings.Default.Upgrade()`).

View File

@@ -0,0 +1,51 @@
---
source_files:
- DataPRO/Modules/Hardware/AddEditHardware/Resources/TranslateExtension.cs
- DataPRO/Modules/Hardware/AddEditHardware/Resources/StringResources.Designer.cs
generated_at: "2026-04-16T04:36:34.790176+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "df6887e304a35dc7"
---
# Resources
## Documentation: `TranslateExtension` Markup Extension
### 1. Purpose
This module provides a WPF `MarkupExtension` (`TranslateExtension`) that enables declarative localization of UI strings in XAML. It allows UI elements (e.g., `TextBlock.Text`, `Button.Content`) to bind to localized string resources defined in `StringResources` by specifying a resource key. Its role is to abstract away manual resource lookup and support runtime culture switching in the `AddEditHardware` modules UI.
### 2. Public Interface
- **`TranslateExtension(string key)`**
Constructor. Accepts a string `key` corresponding to a resource name in `StringResources`. Stores the key for later lookup.
- **`object ProvideValue(IServiceProvider serviceProvider)`**
Overrides `MarkupExtension.ProvideValue`. Performs resource lookup at XAML load time:
- Returns `"#stringnotfound#"` if `_key` is `null` or empty.
- Returns the localized string from `StringResources.ResourceManager.GetString(_key)` if found.
- Returns `"#stringnotfound# <key>"` (e.g., `"#stringnotfound# MyKey"`) if the key is non-empty but no matching resource exists.
### 3. Invariants
- `_key` is immutable after construction (no setter or mutation).
- The extension **always returns a `string`** (per `[MarkupExtensionReturnType(typeof(string))]`).
- Lookup is **case-sensitive** (relies on `ResourceManager.GetString(string)` behavior).
- If a resource key is missing, the fallback string explicitly includes the original key for debugging visibility.
### 4. Dependencies
- **Depends on**:
- `System.Windows.Markup` (for `MarkupExtension` base class).
- `AddEditHardware.Resources.StringResources` (strongly-typed resource class generated from `.resx`).
- `System.Resources.ResourceManager` (used internally via `StringResources.ResourceManager`).
- **Used by**:
- XAML files in the `AddEditHardware` module (e.g., `AddEditHardwareView.xaml`) to localize UI elements.
- No direct runtime dependencies beyond WPF framework and the `StringResources` assembly.
### 5. Gotchas
- **Static resource resolution**: `ProvideValue` is called **once at XAML load time**, not at runtime. Changing `StringResources.Culture` *after* XAML is parsed will **not** update already-bound UI elements.
- **Fallback format**: Missing keys yield `"#stringnotfound# <key>"`, which may appear in UI if keys are misspelled or missing from `.resx`. This is intentional for debugging but may confuse end users.
- **No null-safety for `serviceProvider`**: The implementation does not validate `serviceProvider`, though WPF typically provides a valid instance.
- **Hardcoded fallback**: The `"#stringnotfound#"` prefix is hardcoded and not configurable.
- **No async or caching optimization**: Each usage triggers a `ResourceManager.GetString()` call; no caching is applied within `TranslateExtension` (though `ResourceManager` itself caches resources internally).
- **Auto-generated resource class**: `StringResources` is auto-generated; manual edits will be overwritten. Resource keys must match exactly (case-sensitive) with entries in the `.resx` file.
None identified beyond the above.

View File

@@ -0,0 +1,109 @@
---
source_files:
- DataPRO/Modules/Hardware/AddEditHardware/View/AddEditHardwareView.xaml.cs
generated_at: "2026-04-16T04:35:38.785908+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "0ee538e93daa667b"
---
# View
## Documentation: `AddEditHardwareView` (WPF View for Hardware Configuration)
---
### **1. Purpose**
The `AddEditHardwareView` class is the WPF UI view layer for configuring and editing hardware devices in the system. It implements the `IAddEditHardwareView` interface and `INotifyPropertyChanged` to support data binding, and is responsible for rendering hardware type selection, module management (add/remove), and dynamic UI updates based on database version and view model state. It acts as the presentation layer for the `AddEditHardwareViewModel`, coordinating user interactions (e.g., button clicks, selection changes, text input) with the underlying data model via event handlers and property synchronization.
---
### **2. Public Interface**
#### **Properties**
- **`public bool AllowStandin { get; }`**
Determines whether the SLICE6TreeView UI element should be visible. Returns `true` if `DataContext` is null or not an `IAddEditHardwareViewModel`; otherwise, delegates to `vm.AllowStandin`.
- **`public int ViewDbVersion { get; set; }`**
Gets or sets the database version used to filter available hardware types. Setting this clears the cached hardware type list (`_allDASTypes`) and refreshes the `cbHardwareTypes.ItemsSource`.
#### **Methods**
- **`public void Activated()`**
Called when the view is activated. Triggers a property change notification for `AllowStandin`, and if `vm.SLICE6TreeView` is non-null, assigns it to `SLICE6TreeView.Content`.
#### **Event Handlers (Private, but part of public behavior via XAML wiring)**
- **`private void btnRemoveModule_Click(object sender, RoutedEventArgs e)`**
Removes the module associated with the clicked buttons `DataContext` from its owning hardware, then notifies the view model of modification.
- **`private void btnAdd_Click(object sender, RoutedEventArgs e)`**
Adds a new module to the hardware associated with the clicked buttons `DataContext`, then notifies the view model of modification.
- **`private void cb_SelectionChanged(object sender, SelectionChangedEventArgs e)`**,
**`private void cb_Checked(object sender, RoutedEventArgs e)`**,
**`private void cb_Unchecked(object sender, RoutedEventArgs e)`**,
**`private void tb_TextChanged(object sender, TextChangedEventArgs e)`**
All invoke `vm.NotifyModified()` to signal that the underlying data has changed.
#### **Protected/Helper Methods (Not public API, but part of implementation)**
- **`protected bool SetProperty<T>(ref T storage, T value, string propertyName = null)`**
Implements `INotifyPropertyChanged` semantics: updates `storage` only if value differs, raises `PropertyChanged`, and returns `true` if changed.
- **`protected void OnPropertyChanged(string propertyName = null)`**
Raises the `PropertyChanged` event.
---
### **3. Invariants**
- **Thread Safety for Hardware Type Caching**:
`_allDASTypes` is populated and cleared under a `lock` on the static list. `AvailableDASType()` and `PopulateDASTypes()` use this lock to ensure thread-safe initialization and version-based filtering.
- **Database Version Dependency**:
The list of available hardware types (`_allDASTypes`) is *dynamically filtered* based on `ViewDbVersion`. Specific hardware types (e.g., `SLICE6_AIR_BR`, `SLICE6_AIR_TC`, `SLICE_PRO_CAN_FD`) are only included if `ConnectionDbVersion` meets or exceeds their respective version constants (`Constants.SLICE6AIR_BR_DB_VERSION`, etc.).
- **View Model Contract**:
The view assumes `DataContext` is an `IAddEditHardwareViewModel` (or `AddEditHardwareViewModel` in handlers). If not, operations silently exit (e.g., `vm.NotifyModified()` is not called).
- **Module Ownership**:
Module removal (`btnRemoveModule_Click`) requires the `DataContext` of the clicked control to be an `IAddEditHardwareDASModule` with a valid `OwningHardware` reference.
---
### **4. Dependencies**
#### **Imports / Dependencies Used**
- **`DTS.Common`**: Core types, including `Constants`, `DbOperations`, `EnumDescriptionTypeConverter`.
- **`DTS.Common.Converters`**: `EnumDescriptionTypeConverter` used for sorting hardware types by description.
- **`DTS.Common.Enums.Hardware`**: `HardwareTypes`, `SLICEPROSIMConfigurations`, `SLICETCConfigurations`, `RackSizes`.
- **`DTS.Common.Interface.Hardware.AddEditHardware`**: `IAddEditHardwareView`, `IAddEditHardwareViewModel`, `IAddEditHardwareDASModule`, `IAddEditHardwareHardware`.
- **WPF Framework**: `System.Windows`, `System.Windows.Controls`, `System.ComponentModel`.
#### **Assumed Dependencies**
- **`AddEditHardwareViewModel`**: Concrete implementation of `IAddEditHardwareViewModel`, used in handlers (e.g., `vm.NotifyModified()`).
- **XAML file `AddEditHardwareView.xaml`**: Defines UI controls like `cbHardwareTypes`, `cbSliceProSimConfigurations`, `SLICE6TreeView`, etc., which are referenced in code-behind.
- **`Constants` class**: Must define `SLICE6AIR_BR_DB_VERSION`, `SLICE_TC_DB_VERSION`, `SLICE_PRO_CAN_FD_DB_VERSION`, and `MINIMUM_LTS_DB_VERSION`.
---
### **5. Gotchas**
- **Static State Mutation on Version Change**:
Setting `ViewDbVersion` clears `_allDASTypes` *globally*, affecting all instances of `AddEditHardwareView` in the app domain. This is a shared static cache—changing version for one view resets hardware type availability for others.
- **Silent Failures on Invalid Contexts**:
Event handlers (`btnRemoveModule_Click`, `btnAdd_Click`, `cb_*`, `tb_TextChanged`) exit early if `DataContext` is not the expected type or if `ctrlView.DataContext` is not `AddEditHardwareViewModel`. No error is logged or thrown—behavior is silently skipped.
- **`AllowStandin` Logic is Inverted in Edge Cases**:
Returns `true` (i.e., *show* the tree view) when `DataContext` is null or not an `IAddEditHardwareViewModel`. This may be counterintuitive—typically, missing view model would imply *hiding* UI elements.
- **Hardware Type Sorting Relies on Enum Descriptions**:
`_allDASTypes.Sort()` uses `EnumDescriptionTypeConverter.GetEnumDescription()` for ordering. If descriptions are missing, empty, or non-unique, sorting may be inconsistent or throw.
- **No Validation on `ViewDbVersion`**:
`ViewDbVersion` accepts any `int`. If set to a value below `MINIMUM_LTS_DB_VERSION`, behavior is undefined (though `_allDASTypes` is cleared and repopulated using the provided version).
- **Hardcoded Configuration Arrays**:
`_availableSliceProSimConfigurations`, `_availableSliceTCConfigurations`, and `_availableRackSizes` are static and unversioned—no dynamic filtering based on database version is applied to these.
None identified beyond the above.

View File

@@ -0,0 +1,147 @@
---
source_files:
- DataPRO/Modules/Hardware/AddEditHardware/ViewModel/AddEditHardwareViewModel.cs
generated_at: "2026-04-16T04:36:54.084304+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "eb93c7718734fde3"
---
# ViewModel
## Documentation: `AddEditHardwareViewModel`
---
### 1. **Purpose**
This module implements the `AddEditHardwareViewModel` class, which serves as the view model for the Add/Edit Hardware UI flow. It encapsulates the logic for displaying, editing, and saving hardware configuration data (e.g., DAS units, SLICE6 devices), including validation, state management, and integration with other system modules (e.g., SLICE6 tree view, event aggregation, region navigation). It supports two operational modes: *adding* new hardware and *editing* existing hardware, and enforces constraints such as disallowing *StandIn* hardware in contexts where it is not permitted (e.g., data recorders). It acts as the intermediary between the UI (`IAddEditHardwareView`) and the underlying domain model (`IAddEditHardwareHardware`, `IISOHardware`), coordinating persistence and inter-module communication via Prism events.
---
### 2. **Public Interface**
#### `AddEditHardwareViewModel(IAddEditHardwareView view, IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer unityContainer)`
- **Behavior**: Primary constructor. Initializes the view, sets up event subscriptions (`RaiseNotification`, `BusyIndicatorChangeNotification`), and assigns dependencies. Assigns `this` as the views `DataContext`.
#### `AddEditHardwareViewModel()`
- **Behavior**: Parameterless constructor required for XAML binding (e.g., design-time or Unity resolution fallback). Does *not* initialize dependencies.
#### `void SetSLICE6TreeView(ISLICE6TreeView treeView, IHardwareListViewModel treeViewModel)`
- **Behavior**: Injects references to the SLICE6 tree view and its view model. Required for SLICE6-specific operations (e.g., saving associations, reloading tree). May be called after construction.
#### `void Activated()`
- **Behavior**: Called when the view is activated. Enforces that `StandIn` is disabled if `AllowStandin` is `false` and the hardware instance is non-null.
#### `void SetHardware(IDASHardware hw, IISOHardware isoHW)`
- **Behavior**: Initializes or resets the `Hardware` property. If `hw` is `null`, creates a new `Model.Hardware` instance; otherwise, constructs a new `Model.Hardware` from the provided `hw` and `isoHW`.
#### `IISOHardware GetISOHardware()`
- **Behavior**: Converts the internal `Hardware` to an `IISOHardware`. If `Hardware.StandIn` is `true` and `SerialNumber` is not a valid GUID, generates a new GUID, updates both `Hardware.SerialNumber` and `isoHW.SerialNumber`, sets `FirstUseDate` to `null`, `IsFirstUseValid` to `true`, and `CalDate` to `DateTime.Today`.
#### `bool Validate(IISOHardware isoHW, ref List<string> errors, ref List<string> warnings, bool displayWindow, bool IsAdd)`
- **Behavior**: Performs validation on `isoHW`. Checks:
- Serial number validity (`ValidateSerialNumber`)
- Uniqueness of serial number *only if* `IsAdd` is `true` (via `Model.Hardware.CheckUniqueSN`)
- IP address validity (`ValidateIPAddress`)
- Appends error/warning messages to `errors`/`warnings`. Calls `PublishPageError` if `displayWindow` is `true`. Returns `false` if any validation fails.
#### `void PublishPageError(bool displayWindow, List<string> errors, List<string> warnings)`
- **Behavior**: If `displayWindow` is `true` and either `errors` or `warnings` is non-empty, publishes a `PageErrorEvent` with combined messages.
#### `void SaveSLICE6Associations()`
- **Behavior**: If `Hardware.HardwareType` is `SLICE6DB`, `SLICE6DB3`, or `SLICE6DB_InDummy`, calls `SLICE6TreeViewModel.SaveSLICE6Associations(Hardware.SerialNumber)`.
#### `void Save()`
- **Behavior**: Persists the current `Hardware` via `Model.Hardware.Save(...)`, passing `TestId`, and `model.IsAdd`. Then:
- Calls `SaveSLICE6Associations()`
- Publishes a `HardwareSavedEvent` with `(DASId, SerialNumber)`
- Calls `SLICE6TreeViewModel.LoadTreeView(SerialNumber)` if `SLICE6TreeViewModel` is non-null.
#### `void NotifyModified()`
- **Behavior**: If `NotificationsOn` is `true`, publishes a `PageModifiedEvent` with status `Modified`.
#### `void Cleanup()`, `Task CleanupAsync()`, `void Initialize()`, `void Initialize(object)`, `void Initialize(object, object)`, `Task InitializeAsync()`, `Task InitializeAsync(object)`, `void Unset()`
- **Behavior**: No-op stubs. Present to satisfy interface contracts (e.g., `IInitialize`, `ICleanup`), but contain no logic.
#### `void OnPropertyChanged(string propertyName)`
- **Behavior**: Raises the `PropertyChanged` event for the specified property.
#### `event PropertyChangedEventHandler PropertyChanged`
- **Behavior**: Standard `INotifyPropertyChanged` implementation.
#### Properties:
- `bool AllowStandin { get; set; } = true`
Controls whether *StandIn* hardware is permitted. Defaults to `true`. Set externally (e.g., `false` for data recorders).
- `IAddEditHardwareView View { get; set; }`
Reference to the associated view.
- `IAddEditHardwareHardware Hardware { get; set; }`
The current hardware instance. Setting it triggers property change notifications for `Hardware`, `SerialNumber`, `FirmwareVersion`, `IPAddress`, and calls `SLICE6TreeViewModel.LoadTreeView(...)`.
- `int? TestId { get; set; }`
Optional test context ID, used during save.
- `bool NotificationsOn { get; set; } = false`
Enables/disables `PageModifiedEvent` publishing.
- `bool IsBusy { get; set; }`
Bound to busy indicator UI. Set via `OnBusyIndicatorNotification`.
- `bool IsMenuIncluded { get; set; }`, `bool IsNavigationIncluded { get; set; }`
UI layout flags; trigger `OnPropertyChanged` on change.
- `ISLICE6TreeView SLICE6TreeView { get; private set; }`, `IHardwareListViewModel SLICE6TreeViewModel { get; private set; }`
References injected via `SetSLICE6TreeView`. May be `null`.
- `InteractionRequest<Notification> NotificationRequest { get; }`, `InteractionRequest<Confirmation> ConfirmationRequest { get; }`
Prism interaction requests used to show popups (e.g., notifications, confirmations).
---
### 3. **Invariants**
- `Hardware` is never `null`; defaults to `new Model.Hardware()` if `SetHardware(null, ...)` is called.
- `Hardware.StandIn` is forced to `false` during `Activated()` if `AllowStandin` is `false` and `Hardware` is non-null.
- `Hardware.SerialNumber` may be overwritten (replaced with a new GUID) in `GetISOHardware()` if `StandIn` is `true` and the current `SerialNumber` is not a valid GUID.
- `Validate(...)` only enforces serial number uniqueness (`CheckUniqueSN`) when `IsAdd` is `true`.
- `IsBusy` is updated synchronously on the publisher thread via `OnBusyIndicatorNotification(bool)`.
- `SLICE6TreeViewModel` may be `null`; all calls to it are guarded with `?.`.
---
### 4. **Dependencies**
#### Imports / Dependencies:
- **Prism Framework**: `IEventAggregator`, `IRegionManager`, `Unity`, `Prism.Events`, `Prism.Interactivity`, `Prism.Regions`.
- **Common Libraries**:
- `DTS.Common.Events.*` (e.g., `RaiseNotification`, `PageModifiedEvent`, `PageErrorEvent`, `HardwareSavedEvent`)
- `DTS.Common.Interface.Hardware.AddEditHardware` (`IAddEditHardwareView`, `IAddEditHardwareHardware`)
- `DTS.Common.Interface.DataRecorders` (`IDASHardware`, `IISOHardware`)
- `DTS.Common.Interface.DASFactory.Diagnostics` (`ISLICE6TreeView`)
- `DTS.Common.Interface.DASFactory.Diagnostics.HardwareList` (`IHardwareListViewModel`)
- `DTS.Common.Utilities.Logging` (`APILogger`)
- `DTS.Common.Interactivity` (`InteractionRequest<...>`)
- `DTS.Common.Enums.Hardware.HardwareTypes` (used in `SaveSLICE6Associations`)
- **Model Layer**: `Model.Hardware` (internal namespace, used for persistence, conversion, validation, and uniqueness checks).
#### Consumed By:
- `IAddEditHardwareView` (XAML view) binds to this view model.
- Other modules (e.g., `HardwareListViewModel`) may call `SetSLICE6TreeView(...)` to wire SLICE6 tree integration.
- Event subscribers for `PageModifiedEvent`, `PageErrorEvent`, `HardwareSavedEvent`.
---
### 5. **Gotchas**
- **Dual constructors**: The parameterless constructor is required for XAML but leaves dependencies (`_eventAggregator`, `_regionManager`, etc.) uninitialized. Calling methods like `Activated()` or `SetHardware(...)` without prior injection may cause `NullReferenceException`.
- **`GetISOHardware()` mutates state**: If `StandIn` is `true` and `SerialNumber` is not a GUID, it *modifies* `Hardware.SerialNumber` and `isoHW.SerialNumber` in-place. This side effect is not obvious from the method name.
- **`Validate(...)` only checks uniqueness on *add***: `CheckUniqueSN` is skipped during edit (`IsAdd == false`), even if the serial number was changed.
- **`SLICE6TreeViewModel.LoadTreeView(...)` is called on `Hardware` setter**: This may trigger expensive tree reloads even when `Hardware` is set to the same instance (e.g., via property binding updates).
- **`NotificationsOn` defaults to `false`**: `NotifyModified()` does nothing unless explicitly enabled. This may lead to missed “page modified” signals if forgotten.
- **`OnRaiseNotification` strips title from `NotificationContentEventArgs`**: The original `eventArgsWithTitle.Title` is used as the popup title, but the message content is reconstructed with an empty string for the third parameter (likely legacy or for compatibility).
- **No-op lifecycle methods**: `Initialize`, `Cleanup`, etc., are present but empty. Developers may assume they do work; they do not.
- **`IsAdd` is not stored in the view model**: It is passed only to `Validate(...)` and `Save(...)`. If the view model is reused across multiple add/edit operations, `IsAdd` must be tracked externally (e.g., via `parameter` or `model.IsAdd`).
None identified beyond the above.