Files
2026-04-17 14:55:32 -04:00

135 lines
7.8 KiB
Markdown

---
source_files:
- DTS Viewer/DTS.Viewer.Modules/DTS.Viewer.TestModification/ViewModel/TestModificationViewModel.cs
generated_at: "2026-04-16T13:45:56.000728+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "297454e79e1ccbbd"
---
# Documentation: TestModificationViewModel
## 1. Purpose
`TestModificationViewModel` is a Prism-based ViewModel that manages the test modification UI panel in the DTS Viewer application. It enables users to modify test data properties (T0 timing, sensitivity, line fit, descriptions, EU multipliers/offsets, filters, and data flags) for selected channels. The class coordinates between the UI, a sensor calibration database, and the broader application via event aggregation, while enforcing permission-based edit controls and providing undo/redo capabilities for modifications.
---
## 2. Public Interface
### Constructor
```csharp
public TestModificationViewModel(
ITestModificationView view,
IRegionManager regionManager,
IEventAggregator eventAggregator,
IUnityContainer unityContainer)
```
Initializes the ViewModel, sets up the View's DataContext, creates interaction requests, and subscribes to four events: `RaiseNotification`, `GraphSelectedChannelsNotification`, `ShiftT0Event`, and `SetUseZeroForUnfilteredEvent`.
### Properties
| Property | Type | Description |
|----------|------|-------------|
| `View` | `ITestModificationView` | Gets/sets the associated view instance. |
| `Parent` | `IBaseViewModel` | Gets/sets the parent ViewModel reference. |
| `Model` | `TestModificationModel` | The model containing channel modification state. Setting updates the model's `Parent` reference. |
| `PreviewCommand` | `DelegateCommand` | Executes `PreviewMethod()` to preview line fit changes. |
| `WriteCommand` | `DelegateCommand` | Executes `WriteMethod()` to persist modifications after validation and user confirmation. |
| `UndoCommand` | `DelegateCommand` | Executes `UndoMethod()` to revert the last modification. |
| `UndoAllCommand` | `DelegateCommand` | Executes `UndoAllMethod()` to revert all modifications. |
| `TestModificationVisability` | `bool` | Controls visibility of the modification panel; true only when exactly one channel is selected. |
| `IsBackedUp` | `bool` | Indicates whether a backup exists for the current model state. Private setter. |
| `UseISOCodeFilterMapping` | `bool` | When true, forces ISOCode field filter to match channel's SoftwareFilter. Defaults to `false`. |
| `UseZeroForUnfiltered` | `bool` | Gets/sets whether to use zero for unfiltered values. Set via `SetUseZeroForUnfilteredEvent`. |
| `IsFilterEnabled` | `bool` | Gets/sets filter enabled state with property change notification. |
| `HeaderInfo` | `string` | Returns `"TestSummaryRegion"`. |
| `IsBusy` | `bool` | Busy indicator with property change notification. |
| `IsDirty` | `bool` | Dirty state flag. |
| `IsNavigationIncluded` | `bool` | Navigation inclusion flag. |
| `NotificationRequest` | `InteractionRequest<Notification>` | Interaction request for notifications. |
| `ConfirmationRequest` | `InteractionRequest<Confirmation>` | Interaction request for confirmations. |
### Methods
```csharp
public void UpdateDatabaseMethod()
```
Updates calibration in the database. Sets `CalibrationId = -1`, updates `ModifyDate` to `DateTime.Now`, creates a new `SensorCalibration`, inserts via `DbOperations.SensorCalibrationsInsert()`, then refreshes `Model.Cal` from latest database record. Publishes `PageErrorEvent` on failure.
```csharp
public override void Initialize()
```
Empty override.
```csharp
public override void Initialize(object parameter)
```
Sets `Parent` to the provided parameter cast as `IBaseViewModel`.
```csharp
public void PublishChanges()
```
If not populating and `Model.IsModifiedDataFlag` is true, immediately saves the data flag modification and updates `IsBackedUp`. Always publishes `TestModificationChangedEvent` with the current model.
---
## 3. Invariants
1. **Single-Channel Selection**: `TestModificationVisability` is `true` only when `channels.Count == 1 && channels.Count(x => x.IsSelected) == 1`. Multi-channel or no selection disables the modification panel.
2. **T0 Validation**: T0 shifts are validated via `Model.ValidateT0()` before write operations. T0 cannot shift beyond the dataset bounds (addresses case #14661).
3. **Calibration Sorting**: Calibration records are sorted in ascending order by `CalibrationDate`, then by `ModifyDate` as a tiebreaker (see `CompareCalibrations`).
4. **Analog Sensor Calibration Display**: Calibrations are only displayed for sensors where `SensorType == 0` (analog sensors).
5. **Permission-Based Controls**: Edit permissions (`EnableSensitivityControl`, `EnableLineFitControl`, `EnableDescriptionControl`, `EnableEUMultiplierControl`, `EnableEUOffsetControl`, `EnableFilterControl`, `IsT0Enabled`, `IsDataFlagEnabled`) are gated by `IViewerMainViewModel.DoesUserHaveEditPermission`.
6. **Population Guard**: The static `IsPopulating` flag prevents `PublishChanges()` from executing data flag saves during model population.
---
## 4. Dependencies
### This Module Depends On:
- `DTS.Common.Base` (`BaseViewModel<T>`)
- `DTS.Common.Events` (`PageErrorEvent`, `PageErrorArg`, `ShiftT0Event`, `ShiftT0EventArguments`, `TestModificationChangedEvent`, `ShowT0CursorEvent`, `GraphSelectedChannelsNotification`, `GraphSelectedChannelsNotificationArg`, `RaiseNotification`, `SetUseZeroForUnfilteredEvent`)
- `DTS.Common.Interactivity` (`Notification`, `Confirmation`, `NotificationContentEventArgs`, `InteractionRequest<T>`)
- `DTS.Common.Interface` (`IBaseViewModel`, `IViewerMainViewModel`)
- `DTS.Common.Interface.Sensors` (`ISensorDbRecord`, `ISensorCalDbRecord`)
- `DTS.Common.Settings` (`SettingsDB`, `Keys`)
- `DTS.Common.Storage` (implied via `DbOperations`)
- `DTS.Common.Utilities.Logging` (`APILogger`)
- `DTS.SensorDB` (`DbOperations`, `SensorCalibration`)
- `DTS.Viewer.ChartOptions.Model` (channel types)
- `DTS.Viewer.TestModification.Model` (`TestModificationModel`, `TestModelManipulation`)
- `Prism.Commands` (`DelegateCommand`)
- `Prism.Events` (`IEventAggregator`)
- `Prism.Regions` (`IRegionManager`)
- `Unity` (`IUnityContainer`)
### What Depends On This Module:
- `ITestModificationView` (the associated View)
- `ITestModificationViewModel` (interface consumers)
- Event subscribers to `TestModificationChangedEvent`
---
## 5. Gotchas
1. **Typo in Property Name**: `TestModificationVisability` is misspelled (should be "Visibility"). This is a historical naming quirk.
2. **Silent Exception Swallowing**: `GetLatestCalibration()` catches all exceptions and returns `null` without logging. The comment explicitly states: "there's no access to APILogger here, so rather than adding a reference, just eat the error."
3. **Malformed XML Comment**: The `<summary>` tag for `GetLatestCalibration` is not properly closed (uses `<summary>` instead of `</summary>`).
4. **Base Member Hiding**: Multiple properties (`Model`, `IsBusy`, `IsDirty`, `IsNavigationIncluded`, `PropertyChanged`, `OnPropertyChanged`) use the `new` keyword to hide base class members, which may indicate design issues or legacy refactoring.
5. **Static `IsPopulating` Flag**: The `IsPopulating` property is static, meaning it is shared across all instances of `TestModificationViewModel`. This could cause unexpected behavior if multiple instances exist.
6. **Hardcoded CalibrationId**: `UpdateDatabaseMethod()` sets `CalibrationId = -1` before insertion. The significance of `-1` is not documented in source.
7. **Database Setting Fallback**: `UseISOCodeFilterMapping` defaults to `false` but is retrieved from settings in `WriteMethod()` with a default of `true` via `SettingsDB.GetGlobalValueBool("UseISOCodeFilterMapping", true)`. The property default and settings default are inconsistent.
8. **Null Check Inconsistency**: Some null checks use `null == sensor` style while others use `sensor == null` (likely ReSharper-generated variations).