This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,172 @@
---
source_files:
- Common/DTS.CommonCore/Behaviors/StringMetaDataAttr.cs
- Common/DTS.CommonCore/Behaviors/TrimTextBoxBehavior.cs
- Common/DTS.CommonCore/Behaviors/InteractivityTemplate.cs
- Common/DTS.CommonCore/Behaviors/TextBoxPasteBehavior.cs
- Common/DTS.CommonCore/Behaviors/MultiSelectionBehavior.cs
generated_at: "2026-04-16T12:04:47.328170+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "c2b7aea8fc779731"
---
# DTS.Common.Behaviors Namespace Documentation
## 1. Purpose
This module provides a collection of WPF behaviors, attached properties, and utility attributes for the DTS CommonCore library. It enables declarative UI interactions through `System.Windows.Interactivity`, including text trimming on focus loss, multi-selection synchronization for `ListBox` controls, paste command handling for `TextBox` derivatives, and a mechanism for applying behaviors/triggers via data templates. It also provides a reflection-based attribute system for attaching string metadata to enum values and objects.
---
## 2. Public Interface
### StringMetaDataAttr
**Kind:** Class (inherits `Attribute`)
**Purpose:** Stores string metadata on objects or enum members.
| Member | Signature | Description |
|--------|-----------|-------------|
| `MetaData` | `public string MetaData { get; }` | Read-only property containing the stored metadata string. |
| `GetStringMetaData` | `public static string GetStringMetaData(object o)` | Retrieves the `MetaData` value from a `StringMetaDataAttr` applied to the object's member (typically enum values). Returns `null` if no attribute is found or if the object is null. |
**Constructor:** `internal StringMetaDataAttr(string attr)` — Internal constructor; attributes must be applied declaratively.
---
### TrimTextBoxBehavior
**Kind:** Class (inherits `Behavior<TextBox>`)
**Purpose:** Automatically trims whitespace from a `TextBox` when it loses focus.
| Member | Signature | Description |
|--------|-----------|-------------|
| `OnAttached` | `protected override void OnAttached()` | Subscribes to `AssociatedObject.LostFocus`. |
| `OnDetaching` | `protected override void OnDetaching()` | Unsubscribes from `AssociatedObject.LostFocus`. |
**Behavior:** On `LostFocus`, trims `AssociatedObject.Text`. If the trimmed value differs, updates the text and calls `UpdateSource()` on the `TextBox.TextProperty` binding expression.
---
### InteractivityTemplate
**Kind:** Class (inherits `DataTemplate`)
**Purpose:** Marker class for defining interactivity templates in XAML resources. Contains no additional members.
---
### InteractivityItems
**Kind:** Class (inherits `FrameworkElement`)
**Purpose:** Container for behaviors and triggers that can be loaded from an `InteractivityTemplate`.
| Member | Signature | Description |
|--------|-----------|-------------|
| `Triggers` | `public new List<TriggerBase> Triggers { get; }` | Lazy-initialized list of triggers. Hides inherited `Triggers` property. |
| `Behaviors` | `public List<Behavior> Behaviors { get; }` | Lazy-initialized list of behaviors. |
| `TemplateProperty` | `public static readonly DependencyProperty TemplateProperty` | Attached property for assigning an `InteractivityTemplate` to a `DependencyObject`. |
| `GetTemplate` | `public static InteractivityTemplate GetTemplate(DependencyObject obj)` | Gets the attached `Template` property value. |
| `SetTemplate` | `public static void SetTemplate(DependencyObject obj, InteractivityTemplate value)` | Sets the attached `Template` property value. |
**Behavior:** When `TemplateProperty` changes, loads `InteractivityTemplate` content, casts to `InteractivityItems`, and adds all behaviors/triggers to the target via `Interaction.GetBehaviors()` and `Interaction.GetTriggers()`.
---
### TextBoxPasteBehavior
**Kind:** Static class (attached property host)
**Purpose:** Enables handling paste operations via an `ICommand` binding on `TextBox` and custom controls.
| Member | Signature | Description |
|--------|-----------|-------------|
| `PasteCommandProperty` | `public static readonly DependencyProperty PasteCommandProperty` | Attached property of type `ICommand`. |
| `GetPasteCommand` | `public static ICommand GetPasteCommand(DependencyObject target)` | Gets the attached `PasteCommand`. |
| `SetPasteCommand` | `public static void SetPasteCommand(DependencyObject target, ICommand value)` | Sets the attached `PasteCommand`. |
**Behavior:** When `PasteCommand` is set, registers a handler for `CommandManager.ExecutedEvent` on the target `TextBox`. When a paste command (`ApplicationCommands.Paste` or a `RoutedUICommand` with `Name == "Paste"`) is executed, retrieves clipboard text, splits by newlines, and executes the bound command with the `TextBox` as parameter. Errors are published via `PageErrorEvent`.
**Special handling:** Supports `ChannelCodeBuilder` and `ChannelNameBuilder` controls by extracting their `MainEditBox` property.
---
### MultiSelectionBehavior
**Kind:** Class (inherits `Behavior<ListBox>`)
**Purpose:** Synchronizes a `ListBox`'s `SelectedItems` collection with a bound `IList` source.
| Member | Signature | Description |
|--------|-----------|-------------|
| `SelectedItems` | `public IList SelectedItems { get; set; }` | Dependency property for binding the source collection. |
| `SelectedItemsProperty` | `public static readonly DependencyProperty SelectedItemsProperty` | Backing field for `SelectedItems`. |
| `OnAttached` | `protected override void OnAttached()` | Initializes `AssociatedObject.SelectedItems` from bound collection. |
**Behavior:**
- Two-way sync between `ListBox.SelectedItems` and bound `IList`.
- Listens to `INotifyCollectionChanged.CollectionChanged` on source.
- Listens to `ListBox.SelectionChanged` for UI-driven changes.
- Uses `SelectedItemsStatus.SetUpdating()` to suppress notifications during bulk operations.
- Type-checks added items against `selectedItems.GetType().GenericTypeArguments[0]`.
---
## 3. Invariants
- **StringMetaDataAttr:** The `GetStringMetaData` method always returns `null` for null objects or when no attribute is found. It assumes `o.ToString()` returns a valid member name.
- **TrimTextBoxBehavior:** Only updates the binding source when trimming actually changes the text (`trim != AssociatedObject.Text`).
- **InteractivityItems:** The `TemplateProperty` change handler does nothing if `e.NewValue` is `null`.
- **TextBoxPasteBehavior:**
- The paste handler only executes if `command.CanExecute(null)` returns `true`.
- The command receives the `TextBox` as its parameter, not the clipboard text.
- Clipboard text is split by `Environment.NewLine` but the resulting `lines` array is not passed to the command.
- **MultiSelectionBehavior:**
- Uses `_isUpdatingTarget` and `_isUpdatingSource` flags to prevent recursive update loops.
- Items are only added to `SelectedItems` if they pass `type.IsAssignableFrom(item.GetType())`.
- `SelectedItemsStatus.SetUpdating(SelectedItems, false)` is called before adding the last item in bulk additions.
---
## 4. Dependencies
### This module depends on:
- `System.Windows.Interactivity` — Base classes for behaviors (`Behavior<T>`, `TriggerBase`, `Interaction`)
- `System.Windows` — WPF core types (`DependencyObject`, `DependencyProperty`, `FrameworkElement`, `RoutedEventArgs`)
- `System.Windows.Controls``TextBox`, `ListBox`, `SelectionChangedEventArgs`
- `System.Windows.Input``ICommand`, `CommandManager`, `ApplicationCommands`, `ExecutedRoutedEventArgs`
- `DTS.Common.Controls``ChannelCodeBuilder`, `ChannelNameBuilder` (referenced in `TextBoxPasteBehavior`)
- `DTS.Common.Events``PageErrorEvent`, `PageErrorArg` (used for error publishing)
- `DTS.Common.Enums` — Referenced in `MultiSelectionBehavior` (likely contains `SelectedItemsStatus`)
- `DTS.Common.Utilities.Logging``APILogger.Log()` for exception logging
- `Microsoft.Practices.Prism.Events``IEventAggregator`
- `Microsoft.Practices.ServiceLocation``ServiceLocator`
### What depends on this module:
- Cannot be determined from source alone. Consumers would be XAML views or other modules applying these behaviors.
---
## 5. Gotchas
1. **StringMetaDataAttr constructor is internal:** You cannot instantiate this attribute programmatically; it must be applied declaratively at compile time.
2. **TextBoxPasteBehavior clipboard handling:** The clipboard text is retrieved and split into lines, but the `lines` array is never used—the command is executed with the `TextBox` as the parameter. The split operation appears to be dead code.
3. **TextBoxPasteBehavior null check bug:** In `CommandExecuted`, the line `if (null == sender && sender is ChannelCodeBuilder ccb)` is logically incorrect—it checks if `sender` is null AND is a specific type, which can never be true. This appears to be a copy-paste error; the intended check was likely `if (sender is ChannelCodeBuilder ccb)`.
4. **TextBoxPasteBehavior dependency on ServiceLocator:** Uses service locator pattern to resolve `IEventAggregator`, which is an anti-pattern and makes testing harder.
5. **MultiSelectionBehavior type checking:** Assumes `SelectedItems` is a generic `IList<T>` when accessing `GenericTypeArguments[0]`. Will throw `IndexOutOfRangeException` if bound to a non-generic `IList`.
6. **InteractivityItems.Triggers hides inherited member:** The `new` keyword on `Triggers` hides `FrameworkElement.Triggers`. This could cause confusion if the property is accessed via a `FrameworkElement` reference.
7. **MultiSelectionBehavior Reset handling:** When `NotifyCollectionChangedAction.Reset` is received, clears `AssociatedObject.SelectedItems` but does not re-populate from the source collection.