Files
DP44/enriched-qwen3-coder-next/DataPRO/Modules/RegionOfInterest/RegionOfInterestChannels/View.md

172 lines
9.8 KiB
Markdown
Raw Normal View History

2026-04-17 14:55:32 -04:00
---
source_files:
- DataPRO/Modules/RegionOfInterest/RegionOfInterestChannels/View/StateListIndexConverter.cs
- DataPRO/Modules/RegionOfInterest/RegionOfInterestChannels/View/RegionOfInterestChannelsView.xaml.cs
- DataPRO/Modules/RegionOfInterest/RegionOfInterestChannels/View/RegionOfInterestChannelsDataTemplateSelector.cs
- DataPRO/Modules/RegionOfInterest/RegionOfInterestChannels/View/GridViewColumns.cs
generated_at: "2026-04-16T04:34:31.801575+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "b5797f8ba3342db7"
---
# View
## Documentation: RegionOfInterestChannels View Layer
---
### 1. Purpose
This module provides WPF UI infrastructure for rendering and interacting with a `GridView`-based view of region-of-interest (ROI) channel data. It enables dynamic column generation from a data source, per-column type-aware cell templating (e.g., `TextBlock` vs. `CheckBox`), column header interactivity (sorting, filtering, multi-select), and automatic column width adjustment for content-fit. It serves as the view layer in an MVVM pattern, implementing `IRegionOfInterestChannelsView` and delegating user actions to an associated `IRegionOfInterestChannelsViewModel`.
---
### 2. Public Interface
#### `StateListIndexConverter`
**Namespace:** `RegionOfInterestChannels`
**Implements:** `IMultiValueConverter`
- **`Convert(object[] values, Type targetType, object parameter, CultureInfo culture)`**
Converts a 2-element multi-value binding: expects `[0] = IEnumerable<State>`, `[1] = int index`. Returns the `State` at the given index in the collection, or `null` if inputs are invalid or index is out of bounds.
**Note:** Does *not* support `ConvertBack`.
#### `RegionOfInterestChannelsView`
**Namespace:** `RegionOfInterestChannels`
**Implements:** `IRegionOfInterestChannelsView` (partial class)
- **`RegionOfInterestChannelsView()`**
Constructor; calls `InitializeComponent()`.
- **`GridViewColumnHeader_OnClick(object sender, RoutedEventArgs e)`**
Handles column header click events. Extracts the `Tag` from the clicked header (supporting `GridViewColumnHeaderSearchable` or `GridViewColumnHeaderSelectable` types), then invokes `vm.Sort(columnTag, true)` on the `DataContext` if it implements `IRegionOfInterestChannelsViewModel`.
- **`TextBlock_Loaded(object sender, RoutedEventArgs e)`**
Adjusts column width dynamically when a `TextBlock` in a cell is loaded and its content width exceeds the columns current width (only if `Width` is `double.NaN`). Finds the column index via visual tree traversal and temporarily sets `Width = ActualWidth`, then resets to `NaN` to trigger remeasurement.
#### `RegionOfInterestChannelsDataTemplateSelector`
**Namespace:** `RegionOfInterestChannels`
**Inherits:** `DataTemplateSelector`
- **`TextBlockDataTemplate` / `CheckBoxDataTemplate`**
Public properties for the two templates to select between.
- **`SelectTemplate(object item, DependencyObject container)`**
Selects a `DataTemplate` based on the cells underlying data type:
- If `item` is a `ChannelEnabler`, inspects the columns header (as property name) to determine the property type on `item`.
- If type is `string` → returns `TextBlockDataTemplate`; sets `ContentPresenter.Tag` to the property value.
- If type is `boolean` (or other) → returns `CheckBoxDataTemplate`; sets `ContentPresenter.Tag` to the *relative index* of the column among boolean columns (`i - checkStartColumn`).
- If `item` is not a `ChannelEnabler`, defaults to `TextBlockDataTemplate`.
**Note:** Uses reflection (`GetProperty`, `GetValue`, `GetType`) on the `item` and `presenter.Columns[i].Header`. Assumes header text matches property names (with spaces removed).
#### `GridViewColumns` (Static Class)
**Namespace:** `RegionOfInterestChannels`
**Purpose:** Attached property provider for configuring `GridView` columns dynamically from an `ICollectionView` source.
##### Attached Properties:
- **`ColumnsSource`** (`object`)
Source collection (typically `ICollectionView`) whose items define columns. Changing this clears and recreates columns.
- **`CellDataTemplateSelector`** (`DataTemplateSelector`)
Optional selector used to choose per-cell templates.
- **`CellDataTemplate`** (`DataTemplate`)
Fallback template for cells if `CellDataTemplateSelector` is `null`.
- **`HeaderTextMember`** (`string`)
Property name on column source items whose value is used for column header text.
- **`DisplayMember`** (`string`)
Property name on column source items whose value is used as the binding path for cell content (currently commented out in `CreateColumn`).
##### Key Methods (Internal/Static):
- **`CreateColumn(GridView gridView, object columnSource)`**
Constructs a `GridViewColumn` from a `columnSource` item:
- Reads `HeaderTextMember` and `DisplayMember` from `gridView`.
- Determines column header type based on the *column source items* `MemberType` property (retrieved via `GetPropertyValue(columnSource, "MemberType")`):
- `typeof(bool)``GridViewColumnHeaderSelectable` with `SelectAll` event handler.
- `typeof(string)``GridViewColumnHeaderSearchable` with `Search` and `ClickHandler` events.
- Otherwise → plain `string` header.
- Assigns `CellTemplateSelector`, `CellTemplate`, and (commented-out) `DisplayMemberBinding`.
- **`GetPropertyValue(object obj, string propertyName)`**
Helper: uses reflection to get `propertyName` from `obj`.
- **`GetArrayIndex(string fromString)`**
Parses an integer from a string like `"SomeProperty[3]"`, returning `-1` on failure.
##### Event Handlers (Internal):
- **`ColumnsSource_CollectionChanged(...)`**
Syncs `gridView.Columns` with changes (`Add`, `Remove`, `Replace`, `Move`, `Reset`) in the `ColumnsSource` collection.
- **`GridViewColumnHeaderSearchable_OnSearch(...)`**
Invokes `vm.Filter(columnTag, searchTerm)`.
- **`GridViewColumnHeader_OnClick(...)`**
Invokes `vm.Sort(columnTag, true)` (same behavior as `RegionOfInterestChannelsView.GridViewColumnHeader_OnClick`).
- **`GridViewColumnHeaderSelectable_OnSelectAll(...)`**
Parses column index from `columnTag` (e.g., `"Enabled[2]"`), then invokes `vm.SelectAll(columnIndex, isSelected)`.
---
### 3. Invariants
- **Column Source Contract:**
Items in the `ColumnsSource` collection must have:
- A property named `"MemberType"` (e.g., `typeof(string)` or `typeof(bool)`), used to determine header type.
- Properties named by `HeaderTextMember` and `DisplayMember` (if set), or default to `null`.
- **Header Tag Format:**
For `GridViewColumnHeaderSelectable`, the `Tag` must be a string containing an array index in brackets (e.g., `"Enabled[0]"`) to be parsed by `GetArrayIndex`.
- **`StateListIndexConverter` Input Expectation:**
Exactly two values: an `IEnumerable<State>` and an `int`. Any deviation yields `null`.
- **`ChannelEnabler` Assumption:**
`RegionOfInterestChannelsDataTemplateSelector.SelectTemplate` assumes `item` is a `ChannelEnabler` when inspecting property types. Behavior for other types is not defined in source.
- **Column Width Adjustment Scope:**
`TextBlock_Loaded` only adjusts the *first* matching `ContentPresenter` in the row. If multiple `TextBlock`s exist per row, only the first is considered.
---
### 4. Dependencies
#### Dependencies *of* this module:
- **WPF Framework:** `System.Windows`, `System.Windows.Controls`, `System.Windows.Data`, `System.Windows.Media`.
- **Common Libraries:**
- `DTS.Common.Controls` (for `GridViewColumnHeaderSearchable`, `GridViewColumnHeaderSelectable`)
- `DTS.Common.Interface.RegionOfInterest.RegionOfInterestChannels` (for `IRegionOfInterestChannelsView`, `IRegionOfInterestChannelsViewModel`)
- `DTS.Common.Utils` (for `Utils.FindChild<T>`)
#### Dependencies *on* this module:
- **`IRegionOfInterestChannelsViewModel`** must be implemented by the `DataContext` for `RegionOfInterestChannelsView` to handle sorting, filtering, and selection.
- **`State` type** is used by `StateListIndexConverter` (imported from elsewhere in the codebase).
- **`ChannelEnabler` type** is used by `RegionOfInterestChannelsDataTemplateSelector` (imported from elsewhere).
---
### 5. Gotchas
- **`ConvertBack` is Unimplemented:**
`StateListIndexConverter.ConvertBack` throws `NotImplementedException`. It is strictly a one-way converter.
- **`DisplayMemberBinding` is Commented Out:**
In `CreateColumn`, the line setting `column.DisplayMemberBinding` is commented. Cell binding relies entirely on `CellDataTemplateSelector` or `CellDataTemplate`. This may cause confusion if `DisplayMember` is set but unused.
- **Header Property Name Matching:**
`RegionOfInterestChannelsDataTemplateSelector.SelectTemplate` uses `presenter.Columns[i].Header.ToString().Replace(" ", "")` to match property names. If headers contain non-alphanumeric characters beyond spaces, reflection will fail.
- **`MemberType` Property Requirement:**
Column source items *must* expose a `"MemberType"` property (via reflection). If missing or non-`Type`, `columnPropertyType` becomes `null`, causing `checkStartColumn` to be set and defaulting to `CheckBoxDataTemplate`.
- **Duplicate Event Handlers Risk:**
`ColumnsSource_CollectionChanged` adds handlers to `ICollectionView.CollectionChanged` but does not deduplicate if `ColumnsSource` is reassigned to the *same* collection instance. This could lead to multiple handler invocations per event.
- **`TextBlock_Loaded` Fragility:**
Relies on a specific visual tree structure (`GridViewRowPresenter``ContentPresenter``TextBlock`). Changes to control templates may break the width adjustment logic.
- **No Null-Safety for `e?.OriginalSource`:**
In `GridViewColumnHeaderSelectable_OnSelectAll`, `(bool)(e?.OriginalSource ?? false)` may throw `InvalidCastException` if `e.OriginalSource` is not a `bool` or `null`.