init
This commit is contained in:
148
docs/ai/DataPRO/Modules/Channels/ChannelCodes/ViewModel.md
Normal file
148
docs/ai/DataPRO/Modules/Channels/ChannelCodes/ViewModel.md
Normal file
@@ -0,0 +1,148 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/Channels/ChannelCodes/ViewModel/ChannelCodesListViewModel.cs
|
||||
generated_at: "2026-04-17T16:02:02.258497+00:00"
|
||||
model: "zai-org/GLM-5-FP8"
|
||||
schema_version: 1
|
||||
sha256: "4a52e53369e1f84f"
|
||||
---
|
||||
|
||||
# ChannelCodesListViewModel Documentation
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
`ChannelCodesListViewModel` is a Prism-based ViewModel that manages the display, editing, validation, and persistence of Channel Codes in a WPF application. It handles two distinct categories of channel codes—ISO and User—providing separate views for each via a `ViewMode` toggle. The ViewModel supports CRUD operations, multi-selection, copy/paste functionality, sorting, filtering, and event-driven communication with other application components. It implements `IChannelCodesListViewModel` and follows the MVVM pattern with `INotifyPropertyChanged` support.
|
||||
|
||||
---
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `View` | `IChannelCodesListView` | The associated view instance; DataContext is set to this ViewModel in constructor. |
|
||||
| `NotificationRequest` | `InteractionRequest<Notification>` | Used to raise notification dialogs. |
|
||||
| `ConfirmationRequest` | `InteractionRequest<Confirmation>` | Used to raise confirmation dialogs. |
|
||||
| `AllISOChannelCodes` | `List<IChannelCode>` | Complete list of ISO channel codes (unfiltered). |
|
||||
| `AllUserChannelCodes` | `List<IChannelCode>` | Complete list of User channel codes (unfiltered). |
|
||||
| `ISOChannelCodes` | `ObservableCollection<IChannelCode>` | Filtered ISO channel codes bound to the view. |
|
||||
| `UserChannelCodes` | `ObservableCollection<IChannelCode>` | Filtered User channel codes bound to the view. |
|
||||
| `SelectedCodes` | `IChannelCode[]` | Returns selected codes based on current `ViewMode`. |
|
||||
| `Page` | `object` | Page identifier used in event payloads. |
|
||||
| `IsDirty` | `bool` | Indicates unsaved changes. |
|
||||
| `IsBusy` | `bool` | Controls busy indicator state. |
|
||||
| `IsMenuIncluded` | `bool` | Controls menu inclusion. |
|
||||
| `IsNavigationIncluded` | `bool` | Controls navigation inclusion. |
|
||||
| `IsReadOnly` | `bool` | When `true`, disables editing (FB14098). |
|
||||
| `ViewMode` | `ViewModes` | Current view mode (`ISO` or `User`). |
|
||||
| `ISOVisibility` | `Visibility` | Returns `Visible` when `ViewMode.ISO`, else `Collapsed`. |
|
||||
| `UserVisibility` | `Visibility` | Returns `Visible` when `ViewMode.User`, else `Collapsed`. |
|
||||
| `ChannelCodesFunc` | `Func<IList<IChannelCode>>` | Returns `ChannelCode.ChannelCodes`. |
|
||||
| `ShowISOStringBuilder` | `bool` | Controls ISO string builder visibility. |
|
||||
| `UniqueISOCodesRequired` | `bool` | Indicates whether unique ISO codes are required. |
|
||||
| `ShowChannelCodeLookupHelper` | `bool` | Controls channel code lookup helper visibility. |
|
||||
|
||||
### Methods
|
||||
|
||||
| Method | Signature | Description |
|
||||
|--------|-----------|-------------|
|
||||
| `OnPropertyChanged` | `void OnPropertyChanged(string propertyName)` | Raises `PropertyChanged` event. |
|
||||
| `Remove` | `void Remove(IChannelCode channel)` | Removes a channel code; routes to `RemoveISOChannel` or `RemoveUserChannel` based on `CodeType`. Publishes `PageModifiedEvent`. |
|
||||
| `MarkModified` | `void MarkModified(IChannelCode channel)` | Marks a channel as modified; adds a new blank row if modifying the last item. Publishes `PageModifiedEvent`. |
|
||||
| `Unset` | `void Unset()` | Clears all channel code collections. |
|
||||
| `SetPage` | `void SetPage(object page)` | Sets the `Page` identifier for event routing. |
|
||||
| `OnSetActive` | `void OnSetActive()` | Loads existing channel codes from database, populates collections, sorts and filters. |
|
||||
| `Cleanup` | `void Cleanup()` | Empty cleanup method. |
|
||||
| `CleanupAsync` | `Task CleanupAsync()` | Returns `Task.CompletedTask`. |
|
||||
| `Initialize` | `void Initialize()` / `void Initialize(object parameter)` / `void Initialize(object parameter, object model)` | Empty initialization methods. |
|
||||
| `InitializeAsync` | `Task InitializeAsync()` / `Task InitializeAsync(object parameter)` | Return `Task.CompletedTask`. |
|
||||
| `Activated` | `void Activated()` | Empty activation method. |
|
||||
| `ReportErrors` | `void ReportErrors(string[] errors)` | Publishes `PageErrorEvent` with errors and `Page`. |
|
||||
| `Save` | `bool Save()` | Persists all changes using a 4-step process: delete removed codes, update existing, insert new, update IDs. Returns `true` on success. |
|
||||
| `ValidateISO` | `void ValidateISO(ref List<string> errors, ref List<string> warnings)` | Validates ISO channel codes. |
|
||||
| `ValidateUser` | `void ValidateUser(ref List<string> errors, ref List<string> warnings)` | Validates User channel codes. |
|
||||
| `Validate` | `bool Validate(bool bDisplayWindow)` | Validates all codes; optionally displays errors/warnings. Returns `true` if no errors. |
|
||||
| `CopySelected` | `void CopySelected()` | Copies selected codes; inserts copies before the last (blank) row. |
|
||||
| `DeleteSelected` | `void DeleteSelected()` | Deletes selected codes; ensures a blank row remains at the end. |
|
||||
| `SetISOSelection` | `void SetISOSelection(IChannelCode[] channelCodes)` | Sets ISO selection; publishes `PageSelectionChanged` if `ViewMode.ISO`. |
|
||||
| `SetUserSelection` | `void SetUserSelection(IChannelCode[] channelCodes)` | Sets User selection; publishes `PageSelectionChanged` if `ViewMode.User`. |
|
||||
| `Filter` | `void Filter(object columnTag, string searchTerm)` | Filters codes based on column tag (`"ISOCode"`, `"ISOChannelName"`, `"UserCode"`, `"UserChannelName"`). |
|
||||
| `Sort` | `void Sort(object columnTag, bool bColumnClick)` | Sorts codes by column; toggles direction on repeated clicks. |
|
||||
|
||||
### Nested Types
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `enum Fields` | `IsoCode`, `IsoChannelName`, `UserCode`, `UserChannelName` — used for sorting/filtering. |
|
||||
| `enum ViewModes` | `ISO`, `User` — toggles between channel code types. |
|
||||
| `class ChannelComparer : IComparer<IChannelCode>` | Custom comparer using `NaturalStringComparer`; handles null/blank items by sorting them last. |
|
||||
|
||||
---
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
1. **Blank Row Guarantee**: The last item in both `AllISOChannelCodes` and `AllUserChannelCodes` is always a blank `ChannelCode` instance (both `Code` and `Name` are empty). This serves as the "new row" for data entry.
|
||||
|
||||
2. **ISO Code Length**: ISO codes are silently truncated to 16 characters maximum in `ParseText()`.
|
||||
|
||||
3. **Blank Item Sorting**: Items with both `Code` and `Name` empty are always sorted to the end of the list (see `ChannelComparer.Compare`).
|
||||
|
||||
4. **Selection Handling**: Empty selection arrays are ignored and not assigned (FB 18906 guard in `SetISOSelection` and `SetUserSelection`).
|
||||
|
||||
5. **Save Operation Ordering**: The `Save()` method executes in strict order: (1) delete removed codes, (2) update existing codes, (3) insert new codes. This prevents primary key conflicts.
|
||||
|
||||
6. **Event Subscription Pattern**: The static `_bAddListeners` flag ensures event listeners are only registered on the second constructor invocation (see Gotchas).
|
||||
|
||||
---
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### External Dependencies (Imports)
|
||||
|
||||
| Namespace | Purpose |
|
||||
|-----------|---------|
|
||||
| `ChannelCodes.Model` | `ChannelCode` model, `ChannelCodeType` lookup |
|
||||
| `DTS.Common.Enums` | General enumerations |
|
||||
| `DTS.Common.Enums.Channels` | `ChannelEnumsAndConstants` |
|
||||
| `DTS.Common.Events` | `PageModifiedEvent`, `PageErrorEvent`, `PageSelectionChanged` |
|
||||
| `DTS.Common.Events.ChannelCodes` | `RaiseNotification`, `BusyIndicatorChangeNotification`, `TextPastedEvent`, `ChannelCodeCommittedEvent` |
|
||||
| `DTS.Common.Interface.Channels.ChannelCodes` | `IChannelCode`, `IChannelCodesListView`, `IChannelCodesListViewModel` |
|
||||
| `DTS.Common.Utilities.Logging` | `APILogger` |
|
||||
| `DTS.Common.Interactivity` | `InteractionRequest<T>`, `Notification`, `Confirmation` |
|
||||
| `Prism.Events` | `IEventAggregator`, `ThreadOption` |
|
||||
| `Prism.Regions` | `IRegionManager` |
|
||||
| `Unity` | `IUnityContainer` |
|
||||
|
||||
### Event Subscriptions
|
||||
|
||||
| Event | Thread Option | Keep Subscriber Reference |
|
||||
|-------|---------------|---------------------------|
|
||||
| `RaiseNotification` | Default | Default |
|
||||
| `BusyIndicatorChangeNotification` | `PublisherThread` | `true` |
|
||||
| `TextPastedEvent` | Default | Default |
|
||||
| `ChannelCodeCommittedEvent` | `PublisherThread` | `true` |
|
||||
|
||||
### Event Publications
|
||||
|
||||
| Event | Payload |
|
||||
|-------|---------|
|
||||
| `PageModifiedEvent` | `PageModifiedArg` with status (`Modified`/`Saved`) and `Page` |
|
||||
| `PageErrorEvent` | `PageErrorArg` with error messages and `Page` |
|
||||
| `PageSelectionChanged` | `PageSelectionChangedArg` with selection count and `Page` |
|
||||
|
||||
---
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
1. **Static Listener Flag Hack**: The constructor uses a static `_bAddListeners` field to prevent duplicate event subscriptions. The comment explicitly states: *"this is a hack, the app startup is calling this, then the app itself, we only want the app itself to be handling the listeners."* This implies the constructor is invoked twice during application lifecycle, and only the second invocation should register `TextPastedEvent` and `ChannelCodeCommittedEvent` handlers.
|
||||
|
||||
2. **Silent ISO Code Truncation**: In `ParseText()`, ISO codes exceeding 16 characters are silently truncated without warning or error. Users are not notified of this modification.
|
||||
|
||||
3. **Paste Behavior Depends on Tag**: The `PasteIso` and `PasteUser` methods interpret the `tag` parameter to determine whether pasted text should populate the `Code` or `Name` field when single-column data is pasted. The tag must equal `"ISOCode"` or `"UserCode"` (string comparison) to populate the code field.
|
||||
|
||||
4. **Filter Uses Case-Insensitive Contains**: Filtering uses `IndexOf(term, StringComparison.CurrentCultureIgnoreCase)` which performs a substring match, not an exact or startswith match.
|
||||
|
||||
5. **Save Returns False Only on Exception**: The `Save()` method returns `false` only if an exception is caught. Validation errors do not prevent save; callers should call `Validate()` before `Save()`.
|
||||
|
||||
6. **Remove vs DeleteSelected Behavior Difference**: `Remove()` does not automatically add a blank row if removing a non-last item, but `DeleteSelected()` and `RemoveISOChannel`/`RemoveUserChannel` do add a blank row when removing the last item. This ensures the blank row invariant is maintained.
|
||||
Reference in New Issue
Block a user