215 lines
11 KiB
Markdown
215 lines
11 KiB
Markdown
|
|
---
|
||
|
|
source_files:
|
||
|
|
- DTS Viewer/DTS.Viewer.Modules/DTS.Viewer.AddCalculatedChannel/ViewModel/AddCalculatedChannelViewModel.cs
|
||
|
|
generated_at: "2026-04-16T13:58:53.491336+00:00"
|
||
|
|
model: "zai-org/GLM-5-FP8"
|
||
|
|
schema_version: 1
|
||
|
|
sha256: "5cfd5d272102b3bf"
|
||
|
|
---
|
||
|
|
|
||
|
|
# Documentation: AddCalculatedChannelViewModel
|
||
|
|
|
||
|
|
## 1. Purpose
|
||
|
|
|
||
|
|
The `AddCalculatedChannelViewModel` class provides the presentation logic for creating and adding calculated channels to test data within the DTS Viewer application. It supports multiple calculation types including mathematical operations (Integral, Double Integral, Derivative, Sin, Cos), aggregate functions (SUM, Average, Resultant), and specialized biomechanical calculations (3D IR-Tracc variants, HIC - Head Injury Criterion). The ViewModel manages channel selection UI state, validates user inputs, persists calculated channels to `.dts` test files, and coordinates with the event aggregation system for cross-component communication.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. Public Interface
|
||
|
|
|
||
|
|
### Class Declaration
|
||
|
|
```csharp
|
||
|
|
public class AddCalculatedChannelViewModel : BaseViewModel<IAddCalculatedChannelViewModel>, IAddCalculatedChannelViewModel
|
||
|
|
```
|
||
|
|
|
||
|
|
### Constructor
|
||
|
|
```csharp
|
||
|
|
public AddCalculatedChannelViewModel(IAddCalculatedChannelView view, IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer unityContainer)
|
||
|
|
```
|
||
|
|
Initializes the ViewModel with its associated view, region manager for UI composition, event aggregator for pub/sub messaging, and Unity dependency injection container.
|
||
|
|
|
||
|
|
### Public Properties
|
||
|
|
|
||
|
|
| Property | Type | Description |
|
||
|
|
|----------|------|-------------|
|
||
|
|
| `View` | `IBaseView` | The associated view instance; DataContext is set to `this` in constructor. |
|
||
|
|
| `Parent` | `IBaseViewModel` | Parent ViewModel passed during initialization. |
|
||
|
|
| `ContextSearchRegion` | `object` | Context region placeholder. |
|
||
|
|
| `NotificationRequest` | `InteractionRequest<Notification>` | Raises notification dialogs. |
|
||
|
|
| `ConfirmationRequest` | `InteractionRequest<Confirmation>` | Raises confirmation dialogs (hides base member). |
|
||
|
|
| `HeaderInfo` | `string` | Returns `"AddCalculatedChannelRegion"`. |
|
||
|
|
| `IsBusy` | `bool` | Throws `NotImplementedException` on get/set. |
|
||
|
|
| `IsDirty` | `bool` | Throws `NotImplementedException` on get. |
|
||
|
|
| `IsAddCalculatedChannelIncluded` | `bool` | Feature inclusion flag. |
|
||
|
|
| `IncludeGroupNameInISOExport` | `bool` | Controls ISO export format. |
|
||
|
|
| `DefaultDTSEncoding` | `int` | Encoding codepage for DTS file operations. |
|
||
|
|
| `ChannelName` | `string` | Name for the new calculated channel. |
|
||
|
|
| `ChannelDescription` | `string` | Auto-generated description based on selected calculation and channels. |
|
||
|
|
| `IsoCode` | `string` | ISO code identifier; defaults to `"NONE"`. |
|
||
|
|
| `SingleChannelSelectorVisibility` | `bool` | Controls visibility for single-channel selection UI. |
|
||
|
|
| `MultipleChannelSelectorVisibility` | `bool` | Controls visibility for multi-channel selection UI. |
|
||
|
|
| `HICChannelSelectorVisibility` | `bool` | Controls visibility for HIC-specific channel selection. |
|
||
|
|
| `ThreeDIRTRACCVisibility` | `bool` | Controls visibility for 3D IR-Tracc channel selection. |
|
||
|
|
| `CalculationList` | `CalculationHelper[]` | Lazy-initialized list of available calculations. |
|
||
|
|
| `SelectedCalculation` | `CalculationHelper` | Currently selected calculation type; setter updates UI visibility states. |
|
||
|
|
| `ChannelList` | `ObservableCollection<ITestChannel>` | All available input channels. |
|
||
|
|
| `ChannelListObjects` | `ObservableCollection<ChannelHelper>` | Wrapped channel objects with inclusion tracking. |
|
||
|
|
| `SourceChannel` | `ITestChannel` | Selected source channel for single-channel calculations. |
|
||
|
|
| `AvailableHICChannels` | `ChannelHelper[]` | Channels with acceleration units valid for HIC calculation. |
|
||
|
|
| `HICAccelerationX` | `ChannelHelper` | X-axis acceleration channel for HIC. |
|
||
|
|
| `HICAccelerationY` | `ChannelHelper` | Y-axis acceleration channel for HIC. |
|
||
|
|
| `HICAccelerationZ` | `ChannelHelper` | Z-axis acceleration channel for HIC. |
|
||
|
|
| `HICLength` | `int` | HIC calculation length parameter; defaults to `16`. |
|
||
|
|
| `IRTraccChannelList` | `ObservableCollection<ChannelHelper>` | Valid IR-Tracc channels. |
|
||
|
|
| `IRTraccChannel` | `ChannelHelper` | Selected IR-Tracc channel. |
|
||
|
|
| `Pot1ChannelList` | `ObservableCollection<ChannelHelper>` | Valid potentiometer 1 channels. |
|
||
|
|
| `Pot1Channel` | `ChannelHelper` | Selected potentiometer 1 channel. |
|
||
|
|
| `Pot2ChannelList` | `ObservableCollection<ChannelHelper>` | Valid potentiometer 2 channels. |
|
||
|
|
| `Pot2Channel` | `ChannelHelper` | Selected potentiometer 2 channel. |
|
||
|
|
|
||
|
|
### Public Methods
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
public void PublishChanges()
|
||
|
|
```
|
||
|
|
Empty implementation (commented `NotImplementedException`).
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
public override void Initialize()
|
||
|
|
public override void Initialize(object parameter)
|
||
|
|
```
|
||
|
|
Sets `Parent` from parameter and subscribes to events.
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
public override void Activated()
|
||
|
|
```
|
||
|
|
Resets UI state: sets default `SourceChannel`, `IsoCode` to `"NONE"`, `ChannelName` to `"New Channel"`, clears HIC selections, sets `HICLength` to `16`.
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
public override void Cleanup()
|
||
|
|
```
|
||
|
|
Empty implementation.
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
public bool Validate(ref List<string> errors, ref List<string> warnings, bool displayWindow)
|
||
|
|
```
|
||
|
|
Validates channel name and calculation-specific requirements (HIC requires 3 channels; Resultant requires matching units and sample rates).
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
public bool ValidateChannelName()
|
||
|
|
```
|
||
|
|
Returns `true` if `ChannelName` is non-empty.
|
||
|
|
|
||
|
|
### Commands
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
public ICommand AddCalculatedChannelCommand { get; private set; }
|
||
|
|
```
|
||
|
|
Executes `AddCalculatedChannel(object obj)` which validates input, creates calculated channels via `CalculatedChannelCreator.CreateChannels()`, adds them to the test structure, and persists changes to `.dts` files.
|
||
|
|
|
||
|
|
### Public Enum
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
public enum Calculation
|
||
|
|
{
|
||
|
|
[Description("Integral")] Integral = 0,
|
||
|
|
[Description("Double Integral")] DoubleIntegral = 1,
|
||
|
|
[Description("Derivative")] Derivative = 2,
|
||
|
|
[Description("Sin")] Sin = 3,
|
||
|
|
[Description("Cos")] Cos = 4,
|
||
|
|
[Description("3D IR-Tracc")] ThreeDIRTracc = 5,
|
||
|
|
[Description("SUM")] SUM = 6,
|
||
|
|
[Description("Average")] AVE = 7,
|
||
|
|
[Description("3D IR-TRACC Abdomen")] ThreeDIRTraccAbdomen = 8,
|
||
|
|
[Description("3D IR-TRACC Lower Thorax")] ThreeDIRTraccLowerThorax = 9,
|
||
|
|
[Description("Resultant")] Resultant = 10,
|
||
|
|
[Description("HIC")] HIC = 11
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Nested Public Classes
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
public class ChannelHelper : BasePropertyChanged
|
||
|
|
```
|
||
|
|
Wraps `ITestChannel` with `DisplayName`, `ChannelName`, and `IsIncluded` properties for UI binding.
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
public class CalculationHelper
|
||
|
|
```
|
||
|
|
Wraps `Calculation` enum with localized `ToString()` via resource manager.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. Invariants
|
||
|
|
|
||
|
|
1. **Channel Name Validation**: `ChannelName` must be non-null and non-empty for validation to pass.
|
||
|
|
2. **HIC Channel Requirement**: HIC calculation requires all three acceleration channels (`HICAccelerationX`, `HICAccelerationY`, `HICAccelerationZ`) to be non-null.
|
||
|
|
3. **Resultant Channel Consistency**: All channels included in a Resultant calculation must have identical `SensitivityUnits` and `SampleRateHz`.
|
||
|
|
4. **Display Order Preservation**: Channels are sorted by `AbsoluteDisplayOrder` when determining insertion position for new calculated channels.
|
||
|
|
5. **File Backup Behavior**: Backup files (`.dtsbak`) are created only if one does not already exist; original file is preserved.
|
||
|
|
6. **IR-Tracc Channel Eligibility**: IR-Tracc channels must be `AnalogInputChannel` type with valid `LinearizationFormula`, `ZeroMethod` of `None`, non-zero `ZeroPoint`, and non-zero `FactoryExcitationVoltage`.
|
||
|
|
7. **Potentiometer Channel Eligibility**: Pot channels must be `AnalogInputChannel` type with units `"deg"` or `"deg-ang"`, `ZeroMethod` of `None`, and non-zero `FactoryExcitationVoltage`.
|
||
|
|
8. **HIC Channel Filtering**: Only channels with units in `Constants.ACCELERATION_UNITS` are available for HIC selection.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. Dependencies
|
||
|
|
|
||
|
|
### External Dependencies (from imports)
|
||
|
|
- `Prism.Events` - `IEventAggregator` for event pub/sub
|
||
|
|
- `Prism.Regions` - `IRegionManager` for UI region management
|
||
|
|
- `Unity` - `IUnityContainer` for dependency injection
|
||
|
|
- `DTS.Serialization.Test` - Test data structures
|
||
|
|
- `DTS.Serialization.SliceRaw.File` - File I/O for `.dts` files
|
||
|
|
|
||
|
|
### Internal Dependencies
|
||
|
|
- `DTS.Common` / `DTS.Common.Base` - Base classes, constants
|
||
|
|
- `DTS.Common.Classes.Viewer.Commands` - `RelayCommand`
|
||
|
|
- `DTS.Common.DAS.Concepts` - `ITestChannel` interface
|
||
|
|
- `DTS.Common.Enums.Sensors` - `ZeroMethodType`
|
||
|
|
- `DTS.Common.Events` - Event types (`RaiseNotification`, `TestSummaryChangeNotification`, `PageErrorEvent`, `SetSaveButton`, `RefreshTestRequestEvent`)
|
||
|
|
- `DTS.Common.Interactivity` - `InteractionRequest<T>`, `Notification`, `Confirmation`
|
||
|
|
- `DTS.Common.Interface` - `IAddCalculatedChannelView`, `IAddCalculatedChannelViewModel`
|
||
|
|
- `DTS.Common.Utilities.Logging` - `APILogger`
|
||
|
|
- `DTS.Common.Utils` - `Utils` static helpers
|
||
|
|
- `DTS.Slice.Control` - Slice control functionality
|
||
|
|
- `DTS.Viewer.AddCalculatedChannel.Model` - `CalculatedChannelCreator`, `LinearizationFormula`
|
||
|
|
|
||
|
|
### Events Consumed
|
||
|
|
- `RaiseNotification` - Displays notification dialogs
|
||
|
|
- `TestSummaryChangeNotification` - Triggers channel list population
|
||
|
|
|
||
|
|
### Events Published
|
||
|
|
- `PageErrorEvent` - Publishes validation errors/warnings
|
||
|
|
- `SetSaveButton` - Controls save button enabled state
|
||
|
|
- `RefreshTestRequestEvent` - Triggers test data refresh after save
|
||
|
|
- `RaiseNotification` - Displays error messages
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. Gotchas
|
||
|
|
|
||
|
|
1. **NotImplementedException on IsBusy/IsDirty**: Both properties throw on access. These appear to be placeholder implementations that were never completed.
|
||
|
|
|
||
|
|
2. **HIC Save Button Logic Appears Inverted**: In `UpdateSaveButtonVisibility()`, the HIC case sets `IsUsable = true` when channels are null and `IsUsable = false` when all three are set—the opposite of expected behavior:
|
||
|
|
```csharp
|
||
|
|
if (null == HICAccelerationX || null == HICAccelerationY || null == HICAccelerationZ)
|
||
|
|
{
|
||
|
|
_eventAggregator.GetEvent<SetSaveButton>().Publish(new SaveButtonUsability() { IsUsable = true });
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
_eventAggregator.GetEvent<SetSaveButton>().Publish(new SaveButtonUsability() { IsUsable = false });
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
3. **Member Hiding with `new` Keyword**: Several members (`PropertyChanged`, `OnPropertyChanged`, `IsBusy`, `IsDirty`, `ConfirmationRequest`) hide base class members using `new`, which may cause confusion when casting to base types.
|
||
|
|
|
||
|
|
4. **Empty PublishChanges() Method**: The `PublishChanges()` method has a commented-out `NotImplementedException` with no implementation, suggesting incomplete feature work.
|
||
|
|
|
||
|
|
5. **Hardcoded Thread.Sleep**: A 10ms `Thread.Sleep()` is used after file write operations in `AddCalculatedChannel()`—this is a potential code smell for file I/O timing issues.
|
||
|
|
|
||
|
|
6. **Test ID Extraction Fragility**: `GetTestIdFromBinaryFileName()` parses the test ID from binary filenames by looking for `"Ch"` substring; if not found, it uses the entire prefix which may produce incorrect results.
|
||
|
|
|
||
|
|
7. **Duplicate Channel Handling**: When adding a calculated channel, existing channels with the same `ChannelId` are silently removed without user confirmation (logged only).
|