init
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/Channels/ChannelCodes/ChannelCodesModule.cs
|
||||
generated_at: "2026-04-16T04:55:41.104321+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "08f6598fbadc11d8"
|
||||
---
|
||||
|
||||
# ChannelCodes
|
||||
|
||||
### **1. Purpose**
|
||||
The `ChannelCodesModule` is a Prism-based modular component responsible for registering the UI views and view models associated with channel code management within the application. It integrates into the modular architecture by implementing the `IModule` interface and registering its core components—`ChannelCodesListViewModel` and `ChannelCodesListView`—as singleton services in the Unity dependency injection container during module initialization. Additionally, it contributes metadata (name, image, group, and region) to the host application’s UI (e.g., main screen) via custom assembly-level attributes (`ChannelCodesModuleNameAttribute` and `ChannelCodesModuleImageAttribute`), enabling dynamic discovery and presentation of the module.
|
||||
|
||||
---
|
||||
|
||||
### **2. Public Interface**
|
||||
|
||||
#### **Classes & Interfaces**
|
||||
|
||||
- **`ChannelCodesModule : IModule`**
|
||||
*Namespace:* `ChannelCodes`
|
||||
*Purpose:* Prism module entry point for channel codes functionality.
|
||||
- **`ChannelCodesModule(IUnityContainer unityContainer)`**
|
||||
Constructor. Accepts and stores a Unity container reference for later registration of types.
|
||||
- **`void Initialize()`**
|
||||
Registers two types as singletons in the Unity container:
|
||||
- `IChannelCodesListViewModel` → `ChannelCodesListViewModel`
|
||||
- `IChannelCodesListView` → `ChannelCodesListView`
|
||||
Called internally by `RegisterTypes()` (via Prism’s module lifecycle).
|
||||
- **`void OnInitialized(IContainerProvider containerProvider)`**
|
||||
Currently empty; no logic implemented.
|
||||
- **`void RegisterTypes(IContainerRegistry containerRegistry)`**
|
||||
Delegates to `Initialize()` (despite using Prism’s `IContainerRegistry`, it uses the Unity-specific `_unityContainer` internally).
|
||||
|
||||
#### **Assembly-Level Attributes**
|
||||
|
||||
- **`[ChannelCodesModuleName]`**
|
||||
*Applied to assembly.*
|
||||
- **`ChannelCodesModuleNameAttribute : TextAttribute`**
|
||||
- **Constructor `ChannelCodesModuleNameAttribute(string s)`**
|
||||
Sets `AssemblyName` to `AssemblyNames.ChannelCodes.ToString()`.
|
||||
- **`override string AssemblyName { get; }`**
|
||||
Returns `"ChannelCodes"` (value of `AssemblyNames.ChannelCodes.ToString()`).
|
||||
- **`override Type GetAttributeType()`**
|
||||
Returns `typeof(TextAttribute)`.
|
||||
- **`override string GetAssemblyName()`**
|
||||
Returns `AssemblyName`.
|
||||
|
||||
- **`[ChannelCodesModuleImage]`**
|
||||
*Applied to assembly.*
|
||||
- **`ChannelCodesModuleImageAttribute : ImageAttribute`**
|
||||
- **Constructor `ChannelCodesModuleImageAttribute(string s)`**
|
||||
Loads image via `AssemblyInfo.GetImage("ChannelCodes")`.
|
||||
- **`override BitmapImage AssemblyImage { get; }`**
|
||||
Returns the image loaded from `AssemblyInfo.GetImage("ChannelCodes")`.
|
||||
- **`override BitmapImage GetAssemblyImage()`**
|
||||
Returns `AssemblyImage`.
|
||||
- **`override string AssemblyName { get; }`**
|
||||
Returns `"ChannelCodes"`.
|
||||
- **`override string GetAssemblyName()`**
|
||||
Returns `AssemblyName`.
|
||||
- **`override string AssemblyGroup { get; }`**
|
||||
Returns `"Prepare"` (value of `eAssemblyGroups.Prepare.ToString()`).
|
||||
- **`override string GetAssemblyGroup()`**
|
||||
Returns `AssemblyGroup`.
|
||||
- **`override eAssemblyRegion AssemblyRegion { get; }`**
|
||||
Returns `eAssemblyRegion.ChannelCodesRegion`.
|
||||
- **`override eAssemblyRegion GetAssemblyRegion()`**
|
||||
Returns `AssemblyRegion`.
|
||||
- **`override Type GetAttributeType()`**
|
||||
Returns `typeof(ImageAttribute)`.
|
||||
|
||||
---
|
||||
|
||||
### **3. Invariants**
|
||||
|
||||
- The module **must** be loaded *after* the Unity container and `AssemblyInfo` service are available (since `AssemblyInfo.GetImage()` is called during attribute instantiation).
|
||||
- `AssemblyNames.ChannelCodes`, `eAssemblyGroups.Prepare`, and `eAssemblyRegion.ChannelCodesRegion` must be defined and valid in the referenced `DTS.Common` assembly; otherwise, runtime errors will occur during attribute initialization.
|
||||
- The `Initialize()` method assumes `_unityContainer` is non-null and properly configured; no null-check is performed.
|
||||
- The `RegisterTypes()` method’s use of `IContainerRegistry` is misleading—**it ignores the `containerRegistry` parameter** and operates solely on the injected `_unityContainer`. This may cause confusion or failure if Prism’s `IContainerRegistry` is expected to be used.
|
||||
|
||||
---
|
||||
|
||||
### **4. Dependencies**
|
||||
|
||||
#### **Imports / External Dependencies**
|
||||
- **Prism.Modularity** (`IModule`, `IContainerProvider`, `IContainerRegistry`)
|
||||
- **Unity** (`IUnityContainer`)
|
||||
- **DTS.Common** (specifically `AssemblyNames`, `AssemblyInfo`, `eAssemblyGroups`, `eAssemblyRegion`, `TextAttribute`, `ImageAttribute`)
|
||||
- **System.Windows.Media.Imaging** (for `BitmapImage`)
|
||||
- **ChannelCodes** namespace (contains `IChannelCodesListViewModel`, `IChannelCodesListView`, `ChannelCodesListViewModel`, `ChannelCodesListView`—not shown in this file but referenced).
|
||||
|
||||
#### **Depended Upon By**
|
||||
- The host application’s module loading infrastructure (Prism + Unity) to discover and load this module.
|
||||
- UI components (e.g., main screen) that consume `ChannelCodesModuleNameAttribute` and `ChannelCodesModuleImageAttribute` to render module metadata.
|
||||
|
||||
---
|
||||
|
||||
### **5. Gotchas**
|
||||
|
||||
- **Misleading `RegisterTypes` implementation**: Despite implementing Prism’s `RegisterTypes(IContainerRegistry)`, the method ignores `containerRegistry` and uses the Unity-specific `_unityContainer`. This breaks Prism’s intended container abstraction and tightly couples the module to Unity.
|
||||
- **Attribute initialization side effects**: `ChannelCodesModuleImageAttribute` calls `AssemblyInfo.GetImage(...)` in its constructor and property getters. This may cause exceptions if `AssemblyInfo` is not yet initialized or the image resource is missing—especially during design-time or in test environments.
|
||||
- **No validation in `Initialize()`**: Type registrations occur unconditionally. If `IChannelCodesListViewModel` or `IChannelCodesListView` are not implemented, registration will fail silently until resolution time (or throw on first use).
|
||||
- **Redundant/unused constructor parameters**: Both attribute constructors accept a `string s` parameter that is unused (assigned to `_name`/`_img` but never read beyond assignment).
|
||||
- **No documentation for `OnInitialized`**: The empty override suggests incomplete implementation or future extensibility—unclear intent from source alone.
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/Channels/ChannelCodes/Model/ChannelCodeType.cs
|
||||
- DataPRO/Modules/Channels/ChannelCodes/Model/ChannelCode.cs
|
||||
generated_at: "2026-04-16T04:56:25.345352+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "8041292bb801532f"
|
||||
---
|
||||
|
||||
# Model
|
||||
|
||||
## Documentation: ChannelCode Module
|
||||
|
||||
---
|
||||
|
||||
### 1. Purpose
|
||||
This module provides data access and modeling for *channel codes*—lookup values used to categorize or classify channels in the system (e.g., ISO-standardized codes vs. user-defined codes). It defines a base abstract class `ChannelCodeType` for retrieving static type metadata and a concrete class `ChannelCode` that represents individual channel code entries, including persistence operations (insert/update/delete) and caching of ISO codes from a static text file. The module serves as the data layer for channel code management, bridging the database (`sp_ChannelCodeTypeGet`, `sp_ChannelCodesGet`) and file-based ISO code definitions.
|
||||
|
||||
---
|
||||
|
||||
### 2. Public Interface
|
||||
|
||||
#### `ChannelCodeType.GetChannelCodeTypeLookup()`
|
||||
```csharp
|
||||
public static IDictionary<short, string> GetChannelCodeTypeLookup()
|
||||
```
|
||||
Retrieves all channel code types from the database via stored procedure `sp_ChannelCodeTypeGet`. Returns a dictionary mapping `Id` (short) to `CodeType` (string), representing the type categories (e.g., ISO, User). Parameters passed to the stored procedure (`@Id`, `@CodeType`) are null, indicating no filtering.
|
||||
|
||||
#### `ChannelCode` class
|
||||
*Inherits from `DTS.Common.Classes.ChannelCodes.ChannelCode` and implements `IChannelCode`.*
|
||||
|
||||
- **Constructors**
|
||||
- `ChannelCode()`
|
||||
Initializes a new `ChannelCode` with `CodeType = ISO` and registers the `PasteCommand`.
|
||||
- `ChannelCode(IChannelCode channelCode)`
|
||||
Copies properties from an existing `IChannelCode` instance and registers `PasteCommand`.
|
||||
- `ChannelCode(IDataRecord sqlReader, IDictionary<short, string> channelCodeLookup)`
|
||||
Populates the instance from a database row (`sqlReader`) using the provided `channelCodeLookup`. Maps `CodeTypeInt` (short) to a `ChannelCodeType` enum value (`ISO` or `User`) via string comparison against `ChannelEnumsAndConstants.IsoCodeTypeString` and `ChannelEnumsAndConstants.UserCodeTypeString`.
|
||||
|
||||
- **Properties**
|
||||
- `bool HasValidId()`
|
||||
Returns `true` if `Id >= 0`.
|
||||
- `bool IsBlank()`
|
||||
Returns `true` if both `Name` and `Code` are `null` or empty.
|
||||
- `int SelectedChannelType`
|
||||
Gets/sets a legacy dropdown index (0 = ISO, 1 = User) based on `CodeType`. *Deprecated per inline comment.*
|
||||
- `Dictionary<string, string> PossibleChannels { get; private set; }`
|
||||
Publicly readable dictionary (currently unused in source; likely intended for channel mappings).
|
||||
- `static IList<IChannelCode> ChannelCodes { get; }`
|
||||
Returns a combined list of *all* channel codes: user-defined codes (from DB via `GetExistingChannelCodes`) + ISO codes (from `ISOChannelCodes`). Uses a shared lookup from `GetChannelCodeTypeLookup()`.
|
||||
- `static IList<IChannelCode> ISOChannelCodes { get; }`
|
||||
Lazily loads ISO codes from `ISOPossibleChannels.txt` (comma-separated: `Code,Name`). Caches in `_isoChannelCodes` after first access. Thread-safe via `lock(RefreshLock)`.
|
||||
|
||||
- **Methods**
|
||||
- `static ChannelCode[] GetExistingChannelCodes(IDictionary<short, string> lookup)`
|
||||
Fetches all user-defined channel codes from DB via `sp_ChannelCodesGet`, returning an array of `ChannelCode` instances. Parameters passed to the stored procedure (`@Id`, `@Code`, `@Name`, `@CodeType`) are null (no filtering).
|
||||
- `void Delete()`
|
||||
Calls `DbOperations.ChannelCodesDelete(Id, null, null, null)` to remove the channel code *from the lookup table only* (does not affect existing channel instances referencing it).
|
||||
- `void Save(IDictionary<ChannelEnumsAndConstants.ChannelCodeType, short> lookup)`
|
||||
Calls `DbOperations.ChannelCodesUpdate(restrictedLookup, this)` to persist changes to the channel code *lookup table*.
|
||||
- `void Insert(IDictionary<ChannelEnumsAndConstants.ChannelCodeType, short> lookup)`
|
||||
Calls `DbOperations.ChannelCodesInsert(restrictedLookup, this, out id)` to insert a new channel code. On success (`hr == 0`), sets `Id` to the returned value.
|
||||
- `protected static long GetLong(OleDbDataReader reader, string field)`
|
||||
Helper for legacy OleDb access; returns `long.MinValue` on `DBNull`. *Not used in current code.*
|
||||
- `protected static DateTime GetDate(OleDbDataReader reader, string field)`
|
||||
Helper for legacy OleDb access; returns `DateTime.MinValue` on `DBNull`. *Not used in current code.*
|
||||
|
||||
#### Command
|
||||
- `PasteCommand` (public property, type `ICommand`)
|
||||
Initialized as `PasteCommandClass(PASTE_ID)` in `RegisterCommands()`. A no-op `Paste` handler is defined but empty. Registered via `CommandManager.RegisterClassCommandBinding`.
|
||||
|
||||
---
|
||||
|
||||
### 3. Invariants
|
||||
|
||||
- **`Id` validity**: `HasValidId()` requires `Id >= 0`. Negative IDs are considered invalid.
|
||||
- **Code type mapping**: `CodeType` must be either `ChannelEnumsAndConstants.ChannelCodeType.ISO` or `ChannelEnumsAndConstants.ChannelCodeType.User`. Mapping from DB `CodeTypeInt` relies on exact string matches against `IsoCodeTypeString` and `UserCodeTypeString`.
|
||||
- **ISO codes are static**: `ISOChannelCodes` are loaded once and cached in `_isoChannelCodes`. They are *not* persisted to the database.
|
||||
- **Persistence scope**: `Insert`, `Save`, and `Delete` operations affect *only the channel code lookup table*, not any channels that may reference the code.
|
||||
- **Thread safety**: ISO code loading uses `lock(RefreshLock)` to ensure single initialization.
|
||||
- **Null handling**: `IsBlank()` treats `null` and empty strings identically.
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependencies
|
||||
|
||||
#### **Dependencies *of* this module**
|
||||
- **Database**:
|
||||
- Stored procedures: `sp_ChannelCodeTypeGet`, `sp_ChannelCodesGet`
|
||||
- Table columns: `Id`, `Code`, `Name`, `CodeTypeInt`
|
||||
- **File system**:
|
||||
- `ISOPossibleChannels.txt` (comma-separated: `Code,Name`) in app base directory.
|
||||
- **External types**:
|
||||
- `DTS.Common.Storage.DbOperations` (provides `GetSQLCommand`, `ChannelCodesDelete`, `ChannelCodesUpdate`, `ChannelCodesInsert`)
|
||||
- `DTS.Common.Classes.ChannelCodes.ChannelCode` (base class)
|
||||
- `DTS.Common.Interface.Channels.ChannelCodes.IChannelCode` (interface)
|
||||
- `DTS.Common.Enums.Channels.ChannelEnumsAndConstants` (defines `ChannelCodeType`, `IsoCodeTypeString`, `UserCodeTypeString`)
|
||||
- `System.Data.SqlClient`, `System.Data`, `System.IO`, `System.Windows.Input`
|
||||
|
||||
#### **Dependencies *on* this module**
|
||||
- Any module needing channel code metadata or management (e.g., UI dropdowns, channel assignment logic).
|
||||
- `ISOChannelCodes` implies a hard dependency on the presence and format of `ISOPossibleChannels.txt`.
|
||||
|
||||
---
|
||||
|
||||
### 5. Gotchas
|
||||
|
||||
- **`SelectedChannelType` is legacy/deprecated**: The property is tied to a dropdown that may no longer exist. Its use is discouraged.
|
||||
- **`PasteCommand` is non-functional**: The `Paste` handler is empty; the command is registered but does nothing.
|
||||
- **`PossibleChannels` is unused**: The property is declared but never populated in the source.
|
||||
- **ISO codes are *not* persisted**: Changes to `ISOChannelCodes` (e.g., via `Insert`/`Save`) will not affect `ISOPossibleChannels.txt`. This file is read-only at runtime.
|
||||
- **`Delete`/`Save`/`Insert` do not cascade**: Operations affect only the channel code *definition* (lookup), not any existing channels that reference the code.
|
||||
- **Thread-safety limitation**: ISO code loading is thread-safe for initialization, but no caching invalidation mechanism exists (codes are assumed immutable).
|
||||
- **`GetLong`/`GetDate` are dead code**: OleDb-specific helpers with no callers in this module. Likely remnants of legacy migration code.
|
||||
- **`ChannelCodes` property is expensive**: Each access calls `GetChannelCodeTypeLookup()` and `GetExistingChannelCodes()`, which hit the database. Caching externally is recommended if used repeatedly.
|
||||
- **No validation on `Code`/`Name`**: The module does not enforce uniqueness or non-empty values beyond `IsBlank()`. Business rules may be enforced elsewhere.
|
||||
- **`Id` assignment is conditional**: `Insert` only sets `Id` if `hr == 0`; callers must check the return value or handle failure.
|
||||
|
||||
*None identified from source alone.* (Note: The above are inferred from explicit comments and code structure—not hallucinated.)
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/Channels/ChannelCodes/Properties/Settings.Designer.cs
|
||||
- DataPRO/Modules/Channels/ChannelCodes/Properties/AssemblyInfo.cs
|
||||
generated_at: "2026-04-16T04:56:06.604797+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "4a79c622a52c39c9"
|
||||
---
|
||||
|
||||
# Properties
|
||||
|
||||
## Documentation: ChannelCodes.Properties.Settings
|
||||
|
||||
### 1. Purpose
|
||||
This module defines a strongly-typed settings class (`Settings`) for the `ChannelCodes` assembly, enabling centralized access to application-level configuration values via the .NET `ApplicationSettingsBase` infrastructure. It serves as the runtime interface for reading (and potentially writing) user- or application-scoped settings, generated automatically by Visual Studio’s settings designer. The class is internal and sealed, intended solely for use within the `ChannelCodes` module to manage persistent configuration state.
|
||||
|
||||
### 2. Public Interface
|
||||
The module exposes **one public static property**:
|
||||
|
||||
- **`Settings.Default`**
|
||||
- **Signature**: `public static Settings Default { get; }`
|
||||
- **Behavior**: Returns the singleton instance of the `Settings` class, synchronized for thread safety via `ApplicationSettingsBase.Synchronized`. This instance provides access to all application settings defined in the project’s `.settings` file (e.g., `Properties/Settings.settings`). Note: The actual settings properties (e.g., `string SomeSetting { get; set; }`) are *not present in the provided source* and must be defined in the corresponding auto-generated `Settings.cs` (not included here). This file only declares the class skeleton and the `Default` accessor.
|
||||
|
||||
### 3. Invariants
|
||||
- The `Settings` class inherits from `ApplicationSettingsBase`, which enforces standard .NET settings semantics:
|
||||
- Settings values are persisted per-user (user-scoped) or per-application (application-scoped), depending on their `UserScopedSetting`/`ApplicationScopedSetting` attributes (not visible here).
|
||||
- Thread-safety is guaranteed for the `Default` instance via synchronization.
|
||||
- The class is `internal sealed`, meaning it cannot be inherited or accessed outside the `ChannelCodes.Properties` namespace.
|
||||
- The `defaultInstance` field is initialized once during static construction and never reassigned.
|
||||
|
||||
### 4. Dependencies
|
||||
- **Dependencies *of* this module**:
|
||||
- `System.Configuration` (for `ApplicationSettingsBase` and related types).
|
||||
- `System.Runtime.CompilerServices` (for `CompilerGeneratedAttribute`).
|
||||
- `System.CodeDom.Compiler` (for `GeneratedCodeAttribute`).
|
||||
- **Dependencies *on* this module**:
|
||||
- Other parts of the `ChannelCodes` module (or dependent modules) likely consume `Settings.Default` to read configuration values. However, no explicit usages are visible in the provided files.
|
||||
|
||||
### 5. Gotchas
|
||||
- **Auto-generated code**: This file is auto-generated by Visual Studio’s settings designer. Manual edits will be overwritten on regeneration.
|
||||
- **Missing settings definitions**: The provided snippet only shows the class declaration and `Default` property. Actual settings (e.g., `public string ChannelMapPath { get; set; }`) are defined in the corresponding `Settings.Designer.cs` *before* regeneration or in the `.settings` designer file (not included). Without those, `Settings.Default` has no accessible properties beyond inherited `ApplicationSettingsBase` members.
|
||||
- **No write support implied**: While `ApplicationSettingsBase` supports setting values, this file does not indicate whether settings are read-only (application-scoped) or read/write (user-scoped). Behavior depends on attributes in the full `Settings.cs` (not provided).
|
||||
- **Thread-safety scope**: Synchronization applies only to the `Default` instance retrieval—not to individual property access or modification. Concurrent writes to settings properties may still require external locking.
|
||||
- **No versioning or migration logic**: The assembly version (`1.0.0.0`) suggests no settings schema evolution handling is visible here. Migration of settings across versions would require explicit `SettingsUpgrade` logic (absent in this snippet).
|
||||
|
||||
> **Note**: Full behavior (e.g., available settings, their types, scopes, and defaults) cannot be determined from the provided files alone. Consult the `ChannelCodes.Properties.Settings.settings` designer file or the full `Settings.Designer.cs` (which typically contains the property definitions).
|
||||
@@ -0,0 +1,104 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/Channels/ChannelCodes/Resources/TranslateExtension.cs
|
||||
- DataPRO/Modules/Channels/ChannelCodes/Resources/StringResources.Designer.cs
|
||||
generated_at: "2026-04-16T04:55:56.339798+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "3fc30f8d93dc5d3b"
|
||||
---
|
||||
|
||||
# Resources
|
||||
|
||||
## Documentation: `TranslateExtension` Markup Extension
|
||||
|
||||
---
|
||||
|
||||
### **Purpose**
|
||||
|
||||
The `TranslateExtension` class provides a XAML markup extension for localized string lookup within the `ChannelCodes` module. It enables declarative binding of UI text to resource keys defined in `StringResources.resx`, supporting internationalization by resolving keys at runtime using the .NET `ResourceManager`. This allows UI elements (e.g., `TextBlock.Text`, `Button.Content`) to display culture-specific strings without hardcoding values or writing code-behind.
|
||||
|
||||
---
|
||||
|
||||
### **Public Interface**
|
||||
|
||||
#### `TranslateExtension(string key)`
|
||||
**Constructor**
|
||||
- **Parameter**: `key` (`string`) – The resource key to look up (e.g., `"ChannelCode"`, `"DuplicateISOChannelCode"`).
|
||||
- **Behavior**: Stores the key for later resolution. No validation is performed at construction time.
|
||||
|
||||
#### `public override object ProvideValue(IServiceProvider serviceProvider)`
|
||||
**Markup Extension Entry Point**
|
||||
- **Parameter**: `serviceProvider` (`IServiceProvider`) – Provides services to the markup extension (unused in current implementation).
|
||||
- **Returns**:
|
||||
- `string`: The localized string corresponding to `_key`, or
|
||||
- `NotFound` (`"#stringnotfound#"`): If `_key` is `null` or empty,
|
||||
- `NotFound + " " + _key`: If `_key` is non-empty but no matching resource string is found.
|
||||
- **Behavior**:
|
||||
1. Checks if `_key` is `null` or empty → returns `"#stringnotfound#"`.
|
||||
2. Calls `StringResources.ResourceManager.GetString(_key)` to retrieve the localized string.
|
||||
3. If `GetString` returns `null`, appends the key to the `NotFound` prefix (e.g., `"#stringnotfound# MissingISOCode"`).
|
||||
|
||||
> **Note**: The `MarkupExtensionReturnType` attribute indicates this extension always returns a `string`.
|
||||
|
||||
---
|
||||
|
||||
### **Invariants**
|
||||
|
||||
1. **Key Handling**:
|
||||
- Empty or `null` keys are treated as invalid and always resolve to `"#stringnotfound#"`.
|
||||
- Non-empty keys that lack a corresponding resource entry resolve to `"#stringnotfound# <key>"`.
|
||||
2. **Resource Lookup**:
|
||||
- Uses `StringResources.ResourceManager.GetString(key)` with the current UI culture (via `CultureInfo`).
|
||||
- No fallback logic beyond the `null` check in `ProvideValue`.
|
||||
3. **Thread Safety**:
|
||||
- `StringResources.ResourceManager` is lazily initialized and cached (per `StringResources` class), but `TranslateExtension` itself is stateful per instance (stores `_key`). Reuse across threads is safe *only if* the same instance is not shared concurrently (standard for markup extensions).
|
||||
|
||||
---
|
||||
|
||||
### **Dependencies**
|
||||
|
||||
#### **Depends On**
|
||||
- `System.Windows.Markup.MarkupExtension` (WPF framework)
|
||||
- `ChannelCodes.Resources.StringResources` (strongly-typed resource class)
|
||||
- Specifically relies on `StringResources.ResourceManager` and its `GetString(string)` method.
|
||||
- `System` (for `string.IsNullOrEmpty`, `ResourceManager`, `CultureInfo`)
|
||||
|
||||
#### **Used By**
|
||||
- XAML files in the `ChannelCodes` module (e.g., `*.xaml` pages) where localized text is declared via `{local:Translate KeyName}`.
|
||||
- Example usage:
|
||||
```xaml
|
||||
<TextBlock Text="{local:Translate ChannelCode}" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **Gotchas**
|
||||
|
||||
1. **No Resource Key Validation at Compile Time**:
|
||||
- Typos in resource keys (e.g., `"ChannelCodee"` instead of `"ChannelCode"`) will silently resolve to `"#stringnotfound# ChannelCodee"` at runtime.
|
||||
- No build-time or design-time warning is generated for missing keys.
|
||||
|
||||
2. **Hardcoded `NotFound` Prefix**:
|
||||
- The `"#stringnotfound#"` prefix is hardcoded and may be visible in the UI if a key is missing. This is likely intentional for debugging but could confuse end users.
|
||||
|
||||
3. **No Caching of Resolved Strings**:
|
||||
- `ProvideValue` calls `ResourceManager.GetString(_key)` on every invocation. While `ResourceManager` caches resources internally, repeated use of the same key in a UI (e.g., in a `DataTemplate`) may incur unnecessary lookups. Consider caching if performance is critical.
|
||||
|
||||
4. **Culture Handling**:
|
||||
- Respects `StringResources.Culture` (settable via `StringResources.Culture = ...`). If `Culture` is `null`, the UI thread’s `CurrentUICulture` is used.
|
||||
- No explicit handling for fallback cultures (e.g., `en-US` → `en`).
|
||||
|
||||
5. **Auto-Generated Resource Class**:
|
||||
- `StringResources.Designer.cs` is auto-generated. Manual edits will be overwritten. New strings must be added via `.resx` files and regenerated.
|
||||
|
||||
6. **No Support for Format Strings**:
|
||||
- `TranslateExtension` does not support parameterized resources (e.g., `"Error: {0} is missing"`). While `StringResources` has entries like `DuplicateISOChannelCode` (which uses `{0}`), the extension itself does not accept or apply formatting arguments.
|
||||
- To use formatted strings, the caller must manually construct the key (e.g., `"DuplicateISOChannelCode"`), but the resolved string will remain unformatted unless the *caller* applies `string.Format` (not done here).
|
||||
|
||||
7. **WPF-Specific**:
|
||||
- Depends on `System.Windows.Markup`, making it unusable outside WPF (e.g., in MAUI, WinUI, or console apps).
|
||||
|
||||
---
|
||||
|
||||
*Documentation generated from source files dated to .NET Framework 4.0 and WPF. No external dependencies beyond standard .NET libraries.*
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/Channels/ChannelCodes/View/ChannelCodesListView.xaml.cs
|
||||
generated_at: "2026-04-16T04:56:21.286180+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "0dcb0611d2fa879c"
|
||||
---
|
||||
|
||||
# View
|
||||
|
||||
## **1. Purpose**
|
||||
|
||||
This module implements the WPF view layer (`ChannelCodesListView`) for a channel codes management UI, adhering to the `IChannelCodesListView` interface. It provides interactive controls for viewing, editing, sorting, filtering, and selecting channel codes in two distinct modes: ISO and User. The view binds to an `IChannelCodesListViewModel` and handles user interactions such as text edits, checkbox toggles, column header clicks, and selection changes, delegating state management and validation logic to the view model.
|
||||
|
||||
---
|
||||
|
||||
## **2. Public Interface**
|
||||
|
||||
The class `ChannelCodesListView` implements `IChannelCodesListView` (via `partial class` + `: IChannelCodesListView`) and exposes only its constructor publicly. All other members are private event handlers wired via XAML. No public methods or properties are defined in this file.
|
||||
|
||||
### **Constructor**
|
||||
- **`ChannelCodesListView()`**
|
||||
Initializes the WPF component by calling `InitializeComponent()`. Sets up the visual tree defined in `ChannelCodesListView.xaml`.
|
||||
|
||||
All other functionality is exposed indirectly via event handlers attached to XAML elements (e.g., `KeyDown`, `TextChanged`, `SelectionChanged`, `Click`), which internally interact with the `DataContext` (expected to be an `IChannelCodesListViewModel`).
|
||||
|
||||
---
|
||||
|
||||
## **3. Invariants**
|
||||
|
||||
- The `DataContext` **must** be an instance implementing `IChannelCodesListViewModel`; otherwise, most event handlers silently return.
|
||||
- Column sorting and filtering rely on the `Tag` property of `GridViewColumnHeaderSearchable` elements (e.g., `ISOCodeColumnHeader`, `UserCodeColumnHeader`). These tags must be non-null and correspond to valid filter/sort keys expected by the view model.
|
||||
- Selection changes in either `ISOChannelCodesListView` or `UserChannelCodesListView` must result in exactly one `IChannelCode` item being selected per list (based on handler logic in `ISO_Checked`/`User_Checked` and selection handlers), though the code does not enforce uniqueness beyond what the view model allows.
|
||||
- The `ChannelCodeBuilder_OnChannelCodeSelected` handler assumes that if `channelCode.Name` is null/whitespace, it should be overwritten with the selected `name` parameter.
|
||||
- Text/keydown handlers for `ChannelCodeTextBoxUser`, `DisplayNameTextBoxUser`, `ChannelCodeTextBoxIso`, and `DisplayNameTextBoxIso` always call `MarkModified(channelCode)` and then invoke `ValidateUser(...)` or `ValidateISO(...)` with unused `List<string>` parameters—indicating validation results are likely ignored or handled internally by the view model.
|
||||
|
||||
---
|
||||
|
||||
## **4. Dependencies**
|
||||
|
||||
### **Imports / External Types Used**
|
||||
- `System.Collections.Generic`, `System.Windows`, `System.Windows.Controls`, `System.Windows.Media` — standard WPF and .NET types.
|
||||
- `DTS.Common.Controls` — likely contains custom controls (e.g., `GridViewColumnHeaderSearchable`).
|
||||
- `DTS.Common.Enums.Channels` — contains `ChannelEnumsAndConstants.ChannelCodeType`.
|
||||
- `DTS.Common.Interface.Channels.ChannelCodes` — defines `IChannelCodesListView`, `IChannelCodesListViewModel`, `IChannelCode`.
|
||||
- `DTS.Common.Utils` — contains `Utils.FindChild<T>` helper.
|
||||
- `ChannelCodes.Resources.StringResources` — static resource class for localized strings (e.g., `"ISOCode"`, `"UserChannelName"`).
|
||||
|
||||
### **Inferred Dependencies**
|
||||
- **Depends on**:
|
||||
- `IChannelCodesListViewModel` (via `DataContext`) for filtering, sorting, validation, and selection state.
|
||||
- `IChannelCode` interface for individual code objects.
|
||||
- Custom control `GridViewColumnHeaderSearchable` for searchable column headers.
|
||||
- `ChannelCodesListView.xaml` (implicit dependency via `InitializeComponent()`).
|
||||
- **Depended on by**:
|
||||
- Likely consumed by a parent view or shell that binds an `IChannelCodesListViewModel` instance to its `DataContext`.
|
||||
|
||||
---
|
||||
|
||||
## **5. Gotchas**
|
||||
|
||||
- **Silent failures**: Most handlers return early if `DataContext` is not `ChannelCodesListViewModel` (or `IChannelCodesListViewModel`), leading to no-op behavior without logging or exceptions.
|
||||
- **Unused validation outputs**: All `ValidateUser`/`ValidateISO` calls instantiate and pass `new List<string>()` for `out`/`ref` parameters, but the lists are never used—suggesting validation errors are either ignored or handled via side effects (e.g., raising `INotifyDataErrorInfo` or UI bindings).
|
||||
- **Redundant selection handling**: Multiple event handlers (`ISO_Checked`, `User_Checked`, `*SelectionChanged`, `*TextBox*SelectionChanged`) all call `vm.SetISOSelection(...)` or `vm.SetUserSelection(...)`, potentially causing duplicate or conflicting selection updates. This may indicate legacy or overlapping event wiring.
|
||||
- **Hit-test complexity**: `ISOChannelCodesListView_PreviewMouseLeftButtonUp` and `UserChannelCodesListView_PreviewMouseLeftButtonUp` use multiple hit tests (`VisualTreeHelper.HitTest`, `InputHitTest`) and descendant checks to determine sort triggers—fragile and hard to maintain. Sorting is triggered on clicks anywhere in a column header, including `TextBlock`s with specific localized text.
|
||||
- **Commented-out code**: A `ChannelType_SelectionChanged` handler is commented out, suggesting incomplete or deprecated logic.
|
||||
- **Assumed control types**: Handlers assume specific control types (`TextBox`, `ListView`, `TextBlock`, `Control`) and cast them directly—could throw if XAML changes unexpectedly.
|
||||
|
||||
None identified beyond the above.
|
||||
@@ -0,0 +1,233 @@
|
||||
---
|
||||
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 Prism’s 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 it’s 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.
|
||||
Reference in New Issue
Block a user