Files
DP44/enriched-qwen3-coder-next/DataPRO/Modules/Channels/ChannelCodes/ViewModel.md
2026-04-17 14:55:32 -04:00

233 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
source_files:
- DataPRO/Modules/Channels/ChannelCodes/ViewModel/ChannelCodesListViewModel.cs
generated_at: "2026-04-16T04:56:00.828392+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "a1a75e2ca7b7b574"
---
# ViewModel
### **1. Purpose**
The `ChannelCodesListViewModel` class serves as the view model for managing and displaying channel codes (both ISO and User-defined) in a data entry UI. It orchestrates data loading, filtering, sorting, editing (including paste, copy, delete, and validation), and persistence operations for channel codes. It acts as the intermediary between the UI (`IChannelCodesListView`) and the underlying data layer (`ChannelCode`, `ChannelCodeType`), leveraging Prisms event aggregation for decoupled communication and Unity for dependency injection. Its primary role is to expose collections of channel codes (`ISOChannelCodes`, `UserChannelCodes`) and provide methods to manipulate and validate them before saving to the database.
---
### **2. Public Interface**
#### **Properties**
- `IChannelCodesListView View { get; set; }`
Reference to the associated view; view model sets `View.DataContext = this`.
- `InteractionRequest<Notification> NotificationRequest { get; }`
Prism interaction request used to show notification popups (e.g., errors, info).
- `InteractionRequest<Confirmation> ConfirmationRequest { get; }`
Prism interaction request used to prompt for user confirmation (e.g., delete).
- `event PropertyChangedEventHandler PropertyChanged`
Standard `INotifyPropertyChanged` implementation; `OnPropertyChanged` raises it.
- `List<IChannelCode> AllISOChannelCodes { get; set; }`
Full list of ISO channel codes (including blank trailing row), used for sorting/filtering.
- `List<IChannelCode> AllUserChannelCodes { get; set; }`
Full list of User channel codes (including blank trailing row), used for sorting/filtering.
- `ObservableCollection<IChannelCode> ISOChannelCodes { get; set; }`
Filtered/sorted view of `AllISOChannelCodes`, bound to the UI.
- `ObservableCollection<IChannelCode> UserChannelCodes { get; set; }`
Filtered/sorted view of `AllUserChannelCodes`, bound to the UI.
- `ViewModes ViewMode { get; set; }`
Current view mode (`ISO` or `User`). Changing it updates `ISOVisibility`/`UserVisibility`.
- `Visibility ISOVisibility { get; }`
`Visible` if `ViewMode == ViewModes.ISO`, else `Collapsed`.
- `Visibility UserVisibility { get; }`
`Visible` if `ViewMode == ViewModes.User`, else `Collapsed`.
- `bool IsBusy { get; set; }`
Bound to busy indicator; updated via `OnBusyIndicatorNotification`.
- `bool IsDirty { get; private set; }` *(Note: never set in source — likely unused or bug)*
- `bool IsReadOnly { get; set; }`
Controls editability of the view (e.g., based on permissions).
- `bool IsMenuIncluded { get; set; }`, `bool IsNavigationIncluded { get; set; }`
UI layout toggles.
- `object Page { get; private set; }`
Identifier for the page this VM serves (used in events to route to correct consumer).
- `Func<IList<IChannelCode>> ChannelCodesFunc { get; }`
Returns `GetAllChannels()``ChannelCode.ChannelCodes`.
- `bool ShowISOStringBuilder { get; set; }`, `bool ShowChannelCodeLookupHelper { get; set; }`, `bool UniqueISOCodesRequired { get; set; }`
UI configuration flags.
#### **Methods**
- `void SetPage(object page)`
Sets the `Page` identifier used in events.
- `void OnSetActive()`
Loads existing channel codes from DB (`ChannelCode.GetExistingChannelCodes`), populates `AllISOChannelCodes`/`AllUserChannelCodes`, adds blank trailing rows, sorts, filters, and updates `ISOChannelCodes`/`UserChannelCodes`. Logs exceptions.
- `void Unset()`
Clears all channel code collections and raises property change notifications.
- `void Initialize()`, `void Initialize(object)`, `Task InitializeAsync()`, `void Activated()`, `void Cleanup()`, `Task CleanupAsync()`
No-op stubs (likely required by Prism interface contracts).
- `bool Save()`
Persists changes in three steps:
1. Deletes removed codes (those with valid IDs not in `All*ChannelCodes`).
2. Updates existing codes (those with valid IDs).
3. Inserts new codes (those without valid IDs and not blank).
Returns `true` on success; publishes `PageModifiedEvent(Status.Saved)` or `PageErrorEvent` on failure.
- `void Remove(IChannelCode channel)`
Removes a channel from both `All*` and `*ChannelCodes` lists, adds a blank row if the last row was removed, and publishes `PageModifiedEvent(Status.Modified)`.
- `void MarkModified(IChannelCode channel)`
Ensures a blank row is added after the modified channel (if its the last visible row), and publishes `PageModifiedEvent(Status.Modified)`.
- `void Validate(bool bDisplayWindow)`
Validates all ISO/User codes: checks for missing code/name, duplicate code+name pairs. Populates `errors`/`warnings` lists. If `bDisplayWindow`, publishes `PageErrorEvent`. Returns `true` if no errors.
- `void ValidateISO(ref List<string> errors, ref List<string> warnings)`
Validates ISO codes only (calls `CheckChannelCode`).
- `void ValidateUser(ref List<string> errors, ref List<string> warnings)`
Validates User codes only (calls `CheckChannelCode`).
- `void CopySelected()`
Copies selected items (from current `ViewMode`) into `All*ChannelCodes` (before the trailing blank row), then sorts/filters.
- `void DeleteSelected()`
Deletes selected items (from current `ViewMode`), adds blank row if last item deleted, clears selection, and publishes `PageModifiedEvent(Status.Modified)`.
- `void SetISOSelection(IChannelCode[] channelCodes)`, `void SetUserSelection(IChannelCode[] channelCodes)`
Stores selected items; triggers `PageSelectionChanged` event if `ViewMode` matches.
- `IChannelCode[] SelectedCodes { get; }`
Returns selected items for current `ViewMode`.
- `void Filter(object columnTag, string searchTerm)`
Updates `_searchTermForField` and re-applies filter (`FilterIso`/`FilterUser`).
- `void Sort(object columnTag, bool bColumnClick)`
Updates sort field/direction and re-applies sort (`SortIso`/`SortUser`) + filter.
- `void OnRaiseNotification(NotificationContentEventArgs)`
Handles `RaiseNotification` events by raising `NotificationRequest`.
- `void OnBusyIndicatorNotification(bool)`
Updates `IsBusy` property.
- `void ReportErrors(string[] errors)`
Publishes `PageErrorEvent`.
---
### **3. Invariants**
- **Trailing Blank Row**:
`AllISOChannelCodes` and `AllUserChannelCodes` always contain a trailing blank `ChannelCode` (added in `OnSetActive`, `Remove`, `MarkModified`, `Paste*`, `CopySelected`, `DeleteSelected`). This enables adding new entries.
- **Filtering Logic**:
`ISOChannelCodes`/`UserChannelCodes` only include rows where:
- Both `Code` and `Name` are blank, **or**
- `Code`/`Name` matches current search term (case-insensitive substring match).
- **Sorting Logic**:
Sorting uses `ChannelComparer`, which:
- Treats blank rows (empty `Code` and `Name`) as *lowest priority* (sorted to bottom).
- Uses `NaturalStringComparer` for case-insensitive, culture-aware comparison.
- Sorts `Code`/`Name` fields separately for ISO/User modes.
- **Validation Rules**:
A channel code is invalid if:
- `Code` is missing (for non-blank rows) → error.
- `Name` is missing (for non-blank rows) → error.
- Duplicate `Code` + `Name` pair exists → error.
- **Save Order**:
`Save()` processes deletions → updates → inserts to avoid ID/name conflicts.
- **Event Subscription Guard**:
`_bAddListeners` ensures only the *second* instantiation of `ChannelCodesListViewModel` subscribes to `TextPastedEvent`/`ChannelCodeCommittedEvent` (a workaround for app startup ordering).
---
### **4. Dependencies**
#### **Imports/Usings (External Dependencies)**
- `Prism.Events` (`IEventAggregator`, `EventBase`)
- `Prism.Regions` (`IRegionManager`)
- `Unity` (`IUnityContainer`)
- `DTS.Common.*`:
- `Enums.Channels.ChannelEnumsAndConstants`
- `Events.*` (`TextPastedEvent`, `ChannelCodeCommittedEvent`, `PageModifiedEvent`, `PageErrorEvent`, `PageSelectionChanged`)
- `Interface.Channels.ChannelCodes.*` (`IChannelCodesListView`, `IChannelCodesListViewModel`, `IChannelCode`)
- `Utilities.*` (`NaturalStringComparer`, `Logging.APILogger`)
- `Interactivity` (`InteractionRequest<Notification/Confirmation>`)
#### **Internal Dependencies**
- `ChannelCodes.Model` (`ChannelCode`, `ChannelCodeType`)
- `DTS.Common.Enums` (`UIItemStatus`, `PageModifiedArg.Status`)
- `Resources.StringResources` (for localized error messages)
#### **Consumers (Inferred)**
- `ChannelCodesListViewModel` is instantiated via Unity (constructor injection).
- `IChannelCodesListView` binds to its properties/methods.
- Other modules subscribe to its events (`PageModifiedEvent`, `PageErrorEvent`, `PageSelectionChanged`).
- `ChannelCodeCommittedEvent` publisher (e.g., a dialog) calls `OnChannelCodesCommitted`.
---
### **5. Gotchas**
- **`_bAddListeners` Hack**:
A static boolean `_bAddListeners` prevents *first* instantiation from subscribing to events (due to app startup ordering). Only the *second* instance subscribes. This is fragile and non-obvious.
- **`IsDirty` Never Set**:
The `IsDirty` property is declared but never updated (no assignment in source). Likely dead code or incomplete implementation.
- **`SelectedCodes` Null Safety**:
`GetSelectedISOCodes`/`GetSelectedUserCodes` return `null` if `_selectedISOItems`/`_selectedUserItems` are `null`. Consumers must handle `null`.
- **Paste Behavior Depends on `tag`**:
`PasteIso`/`PasteUser` use `tag` to determine if pasted data is `Code` or `Name`-only (via `bCode = tag.Equals("ISOCode")`). If `tag` is incorrect, data may be misassigned.
- **Duplicate Code Handling**:
Validation flags *duplicate code+name pairs* as errors, but allows duplicate codes with *different names*. This may be intentional (e.g., ISO codes can map to multiple names), but could be confusing.
- **`OnChannelCodesCommitted` Logic Complexity**:
The method builds multiple dictionaries (`lookup2`, `isoLookup`, `userLookup`) to avoid duplicates during batch commits. This is error-prone and duplicates logic in `Save()`.
- **`ParseText` Delimiter Fallback**:
Tries to split by `,`, then `\t`, then `;`. If none yield 2 tokens, the line is skipped. This may silently fail if data uses unexpected delimiters.
- **`Validate` Ignores Blank Rows**:
Blank rows (empty `Code`/`Name`) are skipped during validation. This is correct, but the logic is nested inside `CheckChannelCode`.
- **No Undo/Revert**:
Changes are published as `PageModifiedEvent(Status.Modified)` immediately on edit, but no mechanism to revert is visible.
- **`ChannelCodesFunc` Usage Unclear**:
`ChannelCodesFunc` is exposed but its usage (e.g., by `GetAllChannels`) is not shown in this file. Likely consumed externally.
- **`UniqueISOCodesRequired` Flag**:
The property exists but is never used in validation logic (despite its name). May be a future feature flag.
- **`NotifySelectionChanged` Only Notifies When `ViewMode` Matches**:
Selection change events are only published if the current `ViewMode` matches the selection type (ISO/User). This may cause inconsistent selection state if `ViewMode` changes after selection.
- **No Null Checks on `View`**:
`View.DataContext = this` assumes `View` is non-null, but no validation exists.