--- 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`) **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 Triggers { get; }` | Lazy-initialized list of triggers. Hides inherited `Triggers` property. | | `Behaviors` | `public List 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`) **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`, `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` 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.