172 lines
9.5 KiB
Markdown
172 lines
9.5 KiB
Markdown
|
|
---
|
||
|
|
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.
|