Files
DP44/enriched-qwen3-coder-next/Common/DTS.Common/Behaviors.md
2026-04-17 14:55:32 -04:00

152 lines
9.8 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:
- Common/DTS.Common/Behaviors/StringMetaDataAttr.cs
- Common/DTS.Common/Behaviors/TrimTextBoxBehavior.cs
- Common/DTS.Common/Behaviors/InteractivityTemplate.cs
- Common/DTS.Common/Behaviors/TextBoxPasteBehavior.cs
- Common/DTS.Common/Behaviors/MultiSelectionBehavior.cs
generated_at: "2026-04-16T02:55:26.714339+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "13307045704efc6d"
---
# Behaviors
## Documentation: `DTS.Common.Behaviors` Module
---
### 1. Purpose
This module provides a collection of WPF-specific behaviors and utility attributes to extend UI control functionality and metadata handling in the DTS application. It enables declarative attachment of common UI patterns—such as text trimming on `TextBox` controls, paste interception with custom command execution, and bidirectional synchronization of multi-selection state between a `ListBox` and an external `IList`—without requiring code-behind. Additionally, it offers a generic attribute (`StringMetaDataAttr`) for attaching string-based metadata to types or enum values via reflection, and a framework (`InteractivityTemplate`) for packaging and reusing collections of behaviors and triggers as reusable XAML templates.
---
### 2. Public Interface
#### `StringMetaDataAttr`
- **`public string MetaData { get; }`**
Immutable property storing the attached metadata string.
- **`internal StringMetaDataAttr(string attr)`**
Constructor (internal) to initialize `MetaData`.
- **`public static string GetStringMetaData(object o)`**
Retrieves the `MetaData` string from a `StringMetaDataAttr` applied to the *member* (field/property) corresponding to `o.ToString()` (e.g., for an `enum` value, looks up the enum *field*). Returns `null` if no attribute found or reflection fails.
#### `TrimTextBoxBehavior`
- **`public class TrimTextBoxBehavior : Behavior<TextBox>`**
Attaches to a `TextBox` and trims leading/trailing whitespace from its `Text` property on `LostFocus`. If trimming occurs, it updates the binding source.
#### `InteractivityTemplate`
- **`public class InteractivityTemplate : DataTemplate`**
A no-op subclass of `DataTemplate`, used as a marker type for XAML-based interactivity templates.
- **`public class InteractivityItems : FrameworkElement`**
Holds collections of `Behavior`s and `TriggerBase`s. Exposes:
- **`public List<TriggerBase> Triggers { get; }`**
Lazy-initialized list for triggers.
- **`public List<Behavior> Behaviors { get; }`**
Lazy-initialized list for behaviors.
- **`public static readonly DependencyProperty TemplateProperty`**
Attached dependency property `"Template"` of type `InteractivityTemplate`.
- **`public static InteractivityTemplate GetTemplate(DependencyObject obj)` / `SetTemplate(...)`**
Accessors for the `Template` attached property. When set, loads the `InteractivityTemplate`s content (expected to be an `InteractivityItems` instance), and copies its `Behaviors` and `Triggers` into the target object via `Interaction.GetBehaviors(obj)` and `Interaction.GetTriggers(obj)`.
#### `TextBoxPasteBehavior`
- **`public static readonly DependencyProperty PasteCommandProperty`**
Attached dependency property for `PasteCommand`.
- **`public static ICommand GetPasteCommand(DependencyObject target)` / `SetPasteCommand(...)`**
Get/set the `PasteCommand` attached property.
- **Behavior**:
When `PasteCommand` is set on a `TextBox`, `ChannelCodeBuilder`, or `ChannelNameBuilder` (using their `MainEditBox`), it:
- Subscribes to `CommandManager.ExecutedEvent` for `Paste` commands.
- On paste execution, retrieves clipboard text (though *not used* in current implementation).
- Invokes `PasteCommand.Execute(textBox)` if `CanExecute(null)` returns `true`.
- Sets `e.Handled = true` to suppress default paste.
- On error, publishes a `PageErrorEvent` via Prisms `IEventAggregator`.
#### `MultiSelectionBehavior`
- **`public class MultiSelectionBehavior : Behavior<ListBox>`**
Synchronizes selection state between a `ListBox.SelectedItems` and an external `IList` (typically `ObservableCollection<T>` or `BulkObservableCollection<T>`).
- **`public IList SelectedItems { get; set; }`**
Dependency property backing the external list to sync with.
- **Key behaviors**:
- On attach: Populates `ListBox.SelectedItems` from `SelectedItems`.
- On `SelectedItems` property change:
- Clears `ListBox.SelectedItems`, repopulates from new value.
- Subscribes to `CollectionChanged` on the new value and `SelectionChanged` on the `ListBox`.
- On `ListBox.SelectionChanged`: Updates `SelectedItems` (external list) with added/removed items.
- Uses `SelectedItemsStatus.SetUpdating(...)` to suppress notifications during bulk updates.
- Special handling for `BulkObservableCollection<IAnalogSensor>` and `BulkObservableCollection<ITestSetup>` via `BulkOperations*` methods to use `AddRange`/`RemoveRange` for efficiency.
- On `SelectedItems.CollectionChanged`: Updates `ListBox.SelectedItems`.
---
### 3. Invariants
- **`StringMetaDataAttr.GetStringMetaData(object o)`**
- Only inspects the *member* named by `o.ToString()` (e.g., for `MyEnum.ValueX`, looks for `MyEnum.ValueX` field/property).
- Returns `null` if `o` is `null`, member lookup fails, or attribute is absent.
- Does *not* inspect attributes on the *type* of `o`, only its *member*.
- **`TrimTextBoxBehavior`**
- Only trims on `LostFocus`. Does *not* trim on input, typing, or `GotFocus`.
- Only updates the binding source if the trimmed text differs from current text.
- **`InteractivityItems.Template`**
- The `InteractivityTemplate.LoadContent()` result *must* be an `InteractivityItems` instance (or compatible), otherwise casting fails.
- Behavior/trigger addition is *additive*—does not clear existing behaviors/triggers on the target object.
- **`TextBoxPasteBehavior`**
- Only handles `ApplicationCommands.Paste` or a `RoutedUICommand` named `"Paste"`.
- Does *not* inspect or modify clipboard content—only invokes the bound `PasteCommand` with the `TextBox` as parameter.
- Relies on `ContainerLocator.Container` being initialized (for `IEventAggregator` resolution); failure here may cause silent logging errors.
- **`MultiSelectionBehavior`**
- Requires `SelectedItems` to be an `IList` (not `IEnumerable`) and ideally `INotifyCollectionChanged` for two-way sync.
- Uses `SelectedItemsStatus.SetUpdating(...)` to signal bulk operations—consumers *must* respect this flag to avoid spurious notifications.
- Type-specific bulk operations (`BulkOperations*`) only apply when `SelectedItems` is a `BulkObservableCollection<T>` with `T` being `IAnalogSensor` or `ITestSetup`.
- `AddItems` and `RemoveItems` methods perform null checks; exceptions during item addition are logged via `APILogger.Log(ex)` but do *not* halt processing.
---
### 4. Dependencies
#### Dependencies *of* this module:
- **WPF**: `System.Windows`, `System.Windows.Controls`, `System.Windows.Input`, `System.Windows.Interactivity` (via `Microsoft.Xaml.Behaviors`).
- **Prism**: `Prism.Ioc`, `Prism.Events` (`IEventAggregator`, `ContainerLocator`).
- **Domain types**:
- `DTS.Common.Controls.ChannelCodeBuilder`, `ChannelNameBuilder` (for `MainEditBox`).
- `DTS.Common.Interface.Sensors.SensorsList.IAnalogSensor`, `ITestSetup`.
- `DTS.Common.Classes.BulkObservableCollection<T>`.
- `DTS.Common.Enums`, `DTS.Common.Utilities.Logging.APILogger`, `SelectedItemsStatus`.
#### Dependencies *on* this module:
- Likely used by UI layers (e.g., XAML views) to attach behaviors declaratively.
- `InteractivityItems.Template` is intended for use in XAML `DataTemplate`s to share interactivity logic across controls.
---
### 5. Gotchas
- **`StringMetaDataAttr.GetStringMetaData`**
- **Misleading name**: Operates on *members* (e.g., enum fields), not the *type* of the object passed. Passing an enum *value* works, but passing a non-enum object (e.g., `new MyClass()`) will likely fail unless `o.ToString()` matches a member name.
- Uses `GetMember(o.ToString())`, which is case-sensitive and may fail if `ToString()` is overridden unexpectedly.
- **`TrimTextBoxBehavior`**
- Does *not* handle `TextChanged` or validation—trimming happens only on `LostFocus`, which may cause UX surprises if binding updates are deferred.
- **`InteractivityItems.Template`**
- `OnTemplateChanged` assumes `LoadContent()` returns an `InteractivityItems` instance. If the XAML template is malformed or returns a different type, a runtime cast exception occurs.
- **`TextBoxPasteBehavior`**
- Clipboard text is retrieved (`Clipboard.GetText()`) but *never used*—the `PasteCommand` receives the `TextBox` as parameter, but the command implementation must handle clipboard content itself.
- Uses `ContainerLocator.Container` (static), which may cause issues in test scenarios or if Prism container initialization is delayed.
- **`MultiSelectionBehavior`**
- **Critical**: The `SelectedItems` list *must* be mutable and support `Add`/`Remove`/`Clear`. If its read-only (e.g., `IList` wrapping an array), runtime exceptions occur.
- Bulk operations (`BulkOperations*`) only trigger for *exact* type matches: `BulkObservableCollection<IAnalogSensor>` or `BulkObservableCollection<ITestSetup>`. Other generic instantiations (e.g., `BulkObservableCollection<DerivedSensor>`) fall back to per-item operations.
- `SelectedItemsStatus.SetUpdating(...)` is used internally, but its implementation (`SelectedItemsStatus` class) is *not* provided in the source—consumers must ensure its correctly implemented to avoid infinite loops or missed updates.
- **General**:
- All behaviors assume WPFs `Interaction` service is available (via `Microsoft.Xaml.Behaviors`).
- No explicit disposal/cleanup in `MultiSelectionBehavior` for event handlers beyond `OnDetaching`—re-attaching may cause duplicate subscriptions if not handled carefully.