init
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/Groups/GroupChannelList/ViewModel/GroupChannelListViewModel.cs
|
||||
generated_at: "2026-04-16T04:46:34.697931+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "7af2406ccff6580f"
|
||||
---
|
||||
|
||||
# ViewModel
|
||||
|
||||
**Documentation Page: `GroupChannelListViewModel`**
|
||||
|
||||
---
|
||||
|
||||
### **1. Purpose**
|
||||
|
||||
The `GroupChannelListViewModel` class serves as the core view model for managing channel assignments within the *GroupChannelList* UI module. It orchestrates the display, editing, and synchronization of channel data—linking logical channel definitions (e.g., ISO/user codes, sensor assignments, hardware mappings) to physical test hardware and sensor metadata. It supports operations such as bulk import via text paste, drag-and-drop assignment of sensors and hardware channels, range synchronization across channels on the same DAS, and real-time filtering/sorting. It acts as the intermediary between the view (`IGroupChannelListView`, `IGroupChannelSettingsListView`) and domain models (`IGroup`, `ITestSetup`, `ISensorData`, `IHardwareChannel`), publishing events for UI updates and system-wide state changes.
|
||||
|
||||
---
|
||||
|
||||
### **2. Public Interface**
|
||||
|
||||
#### **Constructor**
|
||||
```csharp
|
||||
public GroupChannelListViewModel(
|
||||
IGroupChannelListView view,
|
||||
IGroupChannelSettingsListView settingsView,
|
||||
IRegionManager regionManager,
|
||||
IEventAggregator eventAggregator,
|
||||
IUnityContainer unityContainer)
|
||||
```
|
||||
- Initializes the view model, wires up views, sets up interaction requests (`NotificationRequest`, `ConfirmationRequest`), and subscribes to events (`RaiseNotification`, `BusyIndicatorChangeNotification`, `TextPastedEvent`).
|
||||
- Initializes `SelectedChannelItems` as an `ObservableCollection<IGroupChannel>`.
|
||||
|
||||
#### **Properties**
|
||||
| Property | Type | Description |
|
||||
|---------|------|-------------|
|
||||
| `View` | `IGroupChannelListView` | Reference to the main channel list view. |
|
||||
| `SettingsView` | `IGroupChannelSettingsListView` | Reference to the channel settings view. |
|
||||
| `NotificationRequest` | `InteractionRequest<Notification>` | Prism interaction request for displaying notifications. |
|
||||
| `ConfirmationRequest` | `InteractionRequest<Confirmation>` | Prism interaction request for confirmation dialogs. |
|
||||
| `PropertyChanged` | `event PropertyChangedEventHandler` | Standard `INotifyPropertyChanged` event. |
|
||||
| `ChannelCount` | `int` | Derived from `AllChannels.Count`; triggers `GroupChannelsChangedEvent` on change. |
|
||||
| `AllChannels` | `IList<IGroupChannel>` | *Internal* full list of channels (including blank trailing channel). |
|
||||
| `Channels` | `IList<IGroupChannel>` | *Internal* list of non-blank channels (used for UI rendering). |
|
||||
| `SettingChannels` | `ObservableCollection<IGroupChannel>` | Sorted, filtered list of non-blank channels for settings view. |
|
||||
| `SelectedChannelItems` | `ObservableCollection<IGroupChannel>` | Currently selected channels (for multi-select operations). |
|
||||
| `SearchTerm` | `string` | Current search filter term. |
|
||||
| `BridgeFilter` | `PossibleFilters` | Bridge-type filter (e.g., `Analog`, `Squib`, `DigitalIn`). |
|
||||
| `UseTestSetupOrder` | `bool` | Whether channels are ordered by `TestSetupOrder` (vs `GroupChannelOrder`). |
|
||||
| `ISOViewMode` | `bool` | Controls display of ISO/user fields. |
|
||||
| `ShowSensorChannelUserValues` | `bool` | Controls visibility of sensor/user-specific fields. |
|
||||
| `AllowSensorPushAndPull` | `bool` | Enables sensor parameter comparison and push/pull UI. |
|
||||
| `UserIsAdmin` | `bool` | Admin status for permission checks. |
|
||||
| `AllowChannelDeletionByNonAdminUser` | `bool` | Whether non-admin users can delete channels. |
|
||||
| `AllowChannelDeletionFromFixedGroup` | `bool` | Whether channels in fixed groups can be deleted. |
|
||||
| `IsBusy` | `bool` | Bound to busy indicator via `BusyIndicatorChangeNotification`. |
|
||||
| `Group` | `IGroup` | *Set externally*; the group currently being edited. |
|
||||
| `TestSetup` | `ITestSetup` | *Set externally*; the test setup currently being edited. |
|
||||
| `Page` | `object` | *Set externally*; the page context (e.g., `GroupsPage`, `TestSetupsPage`). |
|
||||
|
||||
#### **Key Methods**
|
||||
| Method | Signature | Description |
|
||||
|--------|-----------|-------------|
|
||||
| `UpdateRangeLowG` | `public void UpdateRangeLowG(IGroupChannel channelChanged)` | Propagates `RangeLowG` to all other channels on the same DAS that have `RangeModifiableSensorLowG = true`. |
|
||||
| `UpdateRangeARS` | `public void UpdateRangeARS(IGroupChannel channelChanged)` | Propagates `Range` to all other channels on the same DAS that have `RangeModifiableSensorARS = true`. |
|
||||
| `UpdateACCouplingEnabled` | `public void UpdateACCouplingEnabled(IGroupChannel channelChanged)` | Propagates `ACCouplingEnabled` to other channels on the same DAS (casts to `GroupChannel`). |
|
||||
| `DoSensorAssignment` | `public void DoSensorAssignment(IGroupChannel groupChannel, IDragAndDropItem[] sensors)` | Assigns sensors to consecutive channels starting at `groupChannel`. Skips assignment to TSR-AIR channels (except StreamOut/UART). Adds new channels if needed. |
|
||||
| `DoHardwareAssignment` | `public void DoHardwareAssignment(IGroupChannel groupChannel, IHardwareChannel[] hardwareChannels)` | Assigns hardware channels to consecutive channels. Skips assignment to non-blank/non-StreamOut/UART channels if source is TSR-AIR. |
|
||||
| `OnTextPasted` | `public void OnTextPasted(ITextPastedEventArgs args)` | Handles paste events (ID = `GroupChannel.PASTE_ID`). Parses tab/semicolon/comma-delimited text into channels, inserting/updating starting at the sender’s position. |
|
||||
| `ParseText` | `private IEnumerable<IGroupChannel> ParseText(string text, object tag, out bool oneColumn)` | Parses raw text into `IGroupChannel` objects. Supports column mapping via `tag` (e.g., `"GroupName"`, `"ISOCode"`). Handles sensor/hardware lookup via dictionaries. |
|
||||
| `GetSensorSerialNumber` | `private string GetSensorSerialNumber(string channelSensor)` | Extracts serial number from sensor string (e.g., `"strain gauge 1 (SG1)"` → `"SG1"`). |
|
||||
| `CreateGroupIfNeeded` | `public IGroup CreateGroupIfNeeded(ITestSetup testSetup, string groupName)`<br>`private IGroup CreateGroupIfNeeded(string groupName)` | Creates a new group if none exists for `groupName` under `TestSetup`. |
|
||||
| `OnSetActive` | `public void OnSetActive()` | Called when view becomes active. Updates channel group names, compares sensor parameters (`CompareAndMarkChannelParameters`), refreshes view settings/columns, and resets sort/filter state. |
|
||||
| `CompareAndMarkChannelParameters` | `public bool CompareAndMarkChannelParameters(IGroupChannel ch)` | Compares channel parameters (e.g., `Range`, `FilterClass`, `SquibFireMode`) against sensor DB defaults. Marks channel as *different* if mismatched. Returns `true` if any change detected. |
|
||||
| `ResetSettingChannels` | `private void ResetSettingChannels()` | Rebuilds `SettingChannels` from `Channels`, applying sort (via `GroupChannelComparer`), filtering blanks, and setting `DigitalOutDurationMax` for TOM hardware. |
|
||||
| `Unset` | `public void Unset()` | Clears all internal state: `AllChannels`, `Channels`, sensor/hardware lookup dictionaries, filters. |
|
||||
| `ClearAllFilters` | `public void ClearAllFilters()` | Resets `SearchTerm`, `BridgeFilter`, `_filterByField`, `_dontFilterList`, and publishes `ListViewStatusEvent.Unloaded`. |
|
||||
| `PopulateChannels` | `public IDictionary<IGroup, IGroupChannel[]> PopulateChannels(...)` | **Core initialization method.** Loads channels from `Group` or `TestSetup`, populates lookup dictionaries (`_idToSensorDictionary`, `_displayToHardwareChannel`), sets up channel metadata (e.g., `RemoveSensorVisibility`, `DeleteShouldBeEnabled`), and returns `ChannelsForGroup` mapping. |
|
||||
| `MarkModified` | `public void MarkModified(IGroupChannel channel, bool bNotifyChanged = true)` | Handles adding a new blank channel after `channel` (if it’s the last non-blank), updates ordering, and ensures group assignment. |
|
||||
| `Remove` | `public void Remove(IGroupChannel channel, bool notifyChanged = true)` | Removes `channel`, adds a new blank channel if needed, updates group/channel mappings, and triggers `NotifyChannelsChanged`. |
|
||||
| `NotifyChannelsChanged` | `public void NotifyChannelsChanged()` | Publishes `PageModifiedEvent` and `GroupUpdatedEvent`, and updates `ChannelCount`/`AssignedPhysicalChannelCount`. |
|
||||
| `GroupNameChanged` | `public void GroupNameChanged(IGroupChannel channel)` | Updates `TestSetup.ChannelsForGroup` when a channel’s group name changes (removes from old group, adds to new). |
|
||||
| `ReportErrors` | `public void ReportErrors(string[] errors)` | Publishes `PageErrorEvent` with error messages. |
|
||||
| `Clear` | `public void Clear(IGroupChannel channel)` | Calls `channel.Clear()` (resets channel fields to defaults). |
|
||||
| `OnBusyIndicatorNotification` | `private void OnBusyIndicatorNotification(bool eventArg)` | Event handler for `BusyIndicatorChangeNotification`; sets `IsBusy`. |
|
||||
| `OnRaiseNotification` | `private void OnRaiseNotification(NotificationContentEventArgs eventArgsWithTitle)` | Event handler for `RaiseNotification`; wraps message and title into `Notification` for UI. |
|
||||
|
||||
#### **Event Handlers (Private)**
|
||||
- `OnTextPasted`: Handles paste events.
|
||||
- `OnBusyIndicatorNotification`: Updates `IsBusy`.
|
||||
- `OnRaiseNotification`: Triggers `NotificationRequest`.
|
||||
|
||||
#### **Event Properties (Public)**
|
||||
- `PropertyChanged`: Standard property change notification.
|
||||
|
||||
---
|
||||
|
||||
### **3. Invariants**
|
||||
|
||||
- **Channel Ordering**:
|
||||
- `AllChannels` always ends with a blank `GroupChannel` (used for adding new channels).
|
||||
- `Channels` is a subset of `AllChannels` containing only non-blank channels.
|
||||
- Channel ordering is maintained via `TestSetupOrder` (if `UseTestSetupOrder`) or `GroupChannelOrder`.
|
||||
- `DetermineButtonState()` enforces `CanMoveUp`/`CanMoveDown` constraints (first channel cannot move up; last non-blank cannot move down).
|
||||
|
||||
- **Group/Hardware Consistency**:
|
||||
- Channels are associated with a `Group` (from `Group` or `TestSetup`) and `HardwareChannel`.
|
||||
- `GroupChannel.GroupName` must match `Group.DisplayName`.
|
||||
- Hardware assignments to TSR-AIR channels are restricted (only to blank, StreamOut, or UART channels).
|
||||
|
||||
- **Sensor/Hardware Lookup**:
|
||||
- `_idToSensorDictionary`, `_serialNumberToSensorDictionary`, and `_displayToHardwareChannel` must be populated before `PopulateChannels` completes.
|
||||
- Sensor serial numbers are extracted from strings (e.g., `"name (SN)"` → `"SN"`) using `GetSensorSerialNumber`.
|
||||
|
||||
- **Filtering**:
|
||||
- `_dontFilterList` preserves channels during filtering (e.g., after drag/drop or paste).
|
||||
- `Filter()` respects `BridgeFilter`, `SearchTerm`, and per-field filters (`_filterByField`).
|
||||
|
||||
- **Notification & Events**:
|
||||
- `OnPropertyChanged("ChannelCount")` triggers `GroupChannelsChangedEvent`.
|
||||
- `MarkModified`, `Remove`, `NotifyChannelsChanged` publish `PageModifiedEvent` and `GroupUpdatedEvent`.
|
||||
|
||||
---
|
||||
|
||||
### **4. Dependencies**
|
||||
|
||||
#### **External Dependencies (Imports/Usings)**
|
||||
- **Prism Framework**: `IEventAggregator`, `IRegionManager`, `UnityContainer`, `InteractionRequest<T>`, `DelegateCommand`.
|
||||
- **DTS Common Libraries**:
|
||||
- `DTS.Common.Classes.Groups`
|
||||
- `DTS.Common.Enums` (e.g., `PossibleFilters`, `Fields`, `HardwareTypes`)
|
||||
- `DTS.Common.Interface.*` (e.g., `IGroupChannel`, `ISensorData`, `IHardwareChannel`)
|
||||
- `DTS.Common.Events.*` (e.g., `TextPastedEvent`, `PageErrorEvent`)
|
||||
- `DTS.Common.Storage`, `DTS.Common.Converters`, `DTS.Common.Interactivity`
|
||||
|
||||
#### **Key Dependencies**
|
||||
- **Views**: `IGroupChannelListView`, `IGroupChannelSettingsListView`.
|
||||
- **Services**: `IEventAggregator`, `IUnityContainer`, `IRegionManager`.
|
||||
- **Data Sources**: `ITestSetup`, `IGroup`, `ISensorData`, `IDASHardware`, `IChannelSetting`.
|
||||
- **Events Published**:
|
||||
- `GroupChannelsChangedEvent`
|
||||
- `PageModifiedEvent`
|
||||
- `GroupUpdatedEvent`
|
||||
- `PageErrorEvent`
|
||||
- `ListViewStatusEvent`
|
||||
- `AppStatusEvent`
|
||||
- `RaiseNotification`
|
||||
|
||||
#### **Dependents**
|
||||
- `GroupChannelList` view (binds to `View`, `SettingsView`).
|
||||
- Other modules via `GroupChannelsChangedEvent`, `PageModifiedEvent`, `GroupUpdatedEvent`.
|
||||
|
||||
---
|
||||
|
||||
### **5. Gotchas**
|
||||
|
||||
- **TSR-AIR Channel Restrictions**:
|
||||
- Sensor/hardware assignments are blocked for non-StreamOut/UART TSR-AIR channels (see `DoSensorAssignment`, `DoHardwareAssignment`).
|
||||
- Embedded sensors in TSR-AIR units are only added if the unit is not already in the group.
|
||||
|
||||
- **Blank Channel Handling**:
|
||||
- `AllChannels` always ends with a blank channel; `Channels` excludes it.
|
||||
- `MarkModified` and `Remove` manage blank channel insertion/removal to maintain this invariant.
|
||||
|
||||
- **Paste Parsing Ambiguity**:
|
||||
- `ParseText` splits on `,`, `\t`, or `;` (in order) if tokens < 2. Column mapping depends on `tag` (e.g., `"GroupName"`).
|
||||
- `oneColumn` output indicates if only one column was present (used for single-field pastes).
|
||||
|
||||
- **Sensor Serial Number Parsing**:
|
||||
- `GetSensorSerialNumber` assumes serial numbers are enclosed in parentheses (e.g., `"name (SN)"`). If no parentheses, the entire string is used.
|
||||
|
||||
- **Group Name Changes**:
|
||||
- `GroupNameChanged` modifies `TestSetup.ChannelsForGroup` and may remove empty groups. Does *not* publish `PageModifiedEvent` (commented out).
|
||||
|
||||
- **Filtering Behavior**:
|
||||
- `_dontFilterList` is cleared on user-initiated filter changes (`initiatedByUser = true`).
|
||||
- Per-field filters (`_filterByField`) are applied *after* `BridgeFilter` and `SearchTerm`.
|
||||
|
||||
- **Hardware Channel Lookup**:
|
||||
- `_displayToHardwareChannel` uses `channel.ToString(hardware)` as the key (implementation-dependent string representation).
|
||||
|
||||
- **Sensor Constants**:
|
||||
- `CompareAndMarkChannelParameters` skips comparison for test-specific sensors (e.g., `TEST_SPECIFIC_ANALOG_SERIAL`).
|
||||
|
||||
- **Settings View Loading**:
|
||||
- `SettingsViewLoaded` controls whether `SettingChannels` triggers `OnPropertyChanged`.
|
||||
- `SettingChannelsLoaded` publishes `AppStatusEvent` (Busy → Available) during UI initialization.
|
||||
|
||||
- **No-Op Initialization Methods**:
|
||||
- `Initialize`, `InitializeAsync`, `Activated`, `Cleanup`, `CleanupAsync` are stubbed (no implementation).
|
||||
|
||||
- **Range Propagation Scope**:
|
||||
- `UpdateRangeLowG`/`UpdateRangeARS` only propagate within the same `DASId`.
|
||||
- `UpdateACCouplingEnabled` requires `GroupChannel` cast (runtime risk if non-`GroupChannel` instances exist).
|
||||
|
||||
- **Channel Ordering After Paste**:
|
||||
- After paste, `AllChannels[i].TestSetupOrder`/`GroupChannelOrder` is reset to `1 + i` for all non-blank channels.
|
||||
|
||||
- **Resource Strings**:
|
||||
- Uses `Resources.StringResources.TestChannelsGroupName` for default group names in `TestSetup` mode.
|
||||
|
||||
- **Missing Validation**:
|
||||
- `ParseText` does not validate sensor/hardware references beyond existence in dictionaries (e.g., invalid IDs are logged but do not halt processing).
|
||||
|
||||
---
|
||||
|
||||
*Note: All behaviors are derived strictly from the provided source. No external documentation or runtime behavior was assumed.*
|
||||
Reference in New Issue
Block a user