init
This commit is contained in:
180
enriched-qwen3-coder-next/Common/DTS.CommonCore/Behaviors.md
Normal file
180
enriched-qwen3-coder-next/Common/DTS.CommonCore/Behaviors.md
Normal file
@@ -0,0 +1,180 @@
|
||||
---
|
||||
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-16T02:15:57.710410+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "c2b7aea8fc779731"
|
||||
---
|
||||
|
||||
# Behaviors
|
||||
|
||||
## Documentation: `DTS.Common.Behaviors` Module
|
||||
|
||||
---
|
||||
|
||||
### 1. Purpose
|
||||
|
||||
This module provides a set of WPF-specific behaviors and utility attributes to extend UI control functionality and support metadata annotations on types. It enables declarative attachment of cross-cutting concerns—such as text trimming on `TextBox` loss of focus, paste interception with custom command execution, multi-selection synchronization between a `ListBox` and an external `IList`, and dynamic injection of interactivity elements via templates—without modifying control logic directly. The module also includes a generic attribute (`StringMetaDataAttr`) for associating arbitrary string metadata with types or enum values, primarily for documentation or UI labeling purposes.
|
||||
|
||||
---
|
||||
|
||||
### 2. Public Interface
|
||||
|
||||
#### `StringMetaDataAttr`
|
||||
- **`public string MetaData { get; }`**
|
||||
Read-only property storing the metadata string provided at construction.
|
||||
- **`internal StringMetaDataAttr(string attr)`**
|
||||
Internal constructor; sets `MetaData` to `attr`.
|
||||
- **`public static string GetStringMetaData(object o)`**
|
||||
Retrieves the `MetaData` string from a `StringMetaDataAttr` applied to the *enum value* or *type* represented by `o`.
|
||||
- Uses reflection on `o.GetType().GetMember(o.ToString())` to find the member.
|
||||
- Returns `null` if no attribute is found or if `o` is `null`/member not found.
|
||||
|
||||
#### `TrimTextBoxBehavior`
|
||||
- **`public class TrimTextBoxBehavior : Behavior<TextBox>`**
|
||||
Attaches to a `TextBox` and trims its `Text` property on `LostFocus`.
|
||||
- On attachment: subscribes to `LostFocus`.
|
||||
- On `LostFocus`: trims `Text`, updates binding source if changed.
|
||||
- On detachment: unsubscribes from `LostFocus`.
|
||||
|
||||
#### `InteractivityItems`
|
||||
- **`public class InteractivityItems : FrameworkElement`**
|
||||
Holds collections of behaviors and triggers for dynamic injection.
|
||||
- **`public List<TriggerBase> Triggers { get; }`**
|
||||
Lazy-initialized list of triggers.
|
||||
- **`public List<Behavior> Behaviors { get; }`**
|
||||
Lazy-initialized list of behaviors.
|
||||
- **Attached Property: `Template` (`InteractivityTemplate`)**
|
||||
When set on a `DependencyObject`, loads content from the `InteractivityTemplate`, extracts its behaviors/triggers, and adds them to the target object’s `Interaction.GetBehaviors()` and `Interaction.GetTriggers()` collections.
|
||||
|
||||
#### `TextBoxPasteBehavior`
|
||||
- **`public static readonly DependencyProperty PasteCommandProperty`**
|
||||
Attached dependency property for `PasteCommand`.
|
||||
- **`public static ICommand GetPasteCommand(DependencyObject target)`**
|
||||
Gets the `PasteCommand` value.
|
||||
- **`public static void SetPasteCommand(DependencyObject target, ICommand value)`**
|
||||
Sets the `PasteCommand` value.
|
||||
- **`private static void PasteCommandChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)`**
|
||||
Attaches/detaches handler for `CommandManager.ExecutedEvent` on the target `TextBox` (or its `MainEditBox` if `ChannelCodeBuilder`/`ChannelNameBuilder`).
|
||||
- **`private static void CommandExecuted(object sender, RoutedEventArgs e)`**
|
||||
Handles `ApplicationCommands.Paste` (or custom `RoutedUICommand` named `"Paste"`).
|
||||
- Retrieves text from `Clipboard`.
|
||||
- Calls `command.Execute(textBox)` if `command.CanExecute(null)` is true.
|
||||
- Sets `e.Handled = true` to suppress default paste.
|
||||
- On exception, publishes `PageErrorEvent` via `IEventAggregator`.
|
||||
|
||||
#### `MultiSelectionBehavior`
|
||||
- **`public class MultiSelectionBehavior : Behavior<ListBox>`**
|
||||
Synchronizes `SelectedItems` of a `ListBox` with an external `IList`.
|
||||
- **`public IList SelectedItems { get; set; }`**
|
||||
Dependency property backing the external list to sync with.
|
||||
- **`public static readonly DependencyProperty SelectedItemsProperty`**
|
||||
Registered dependency property.
|
||||
- **`private static void SelectedItemsChanged(...)`**
|
||||
Handles changes to `SelectedItems`:
|
||||
- Clears `ListBox.SelectedItems` and repopulates from new value.
|
||||
- Subscribes/unsubscribes to `CollectionChanged` on the new/old value and `SelectionChanged` on `AssociatedObject`.
|
||||
- **`private void SourceCollectionChanged(...)`**
|
||||
Updates `AssociatedObject.SelectedItems` when the external `IList` changes (e.g., via `INotifyCollectionChanged`).
|
||||
- **`private void ListBoxSelectionChanged(...)`**
|
||||
Updates the external `SelectedItems` list when `ListBox` selection changes.
|
||||
- Uses `SelectedItemsStatus.SetUpdating(...)` to suppress notifications during bulk updates.
|
||||
- Skips adding items if already present.
|
||||
- Logs exceptions via `APILogger.Log(ex)`.
|
||||
|
||||
---
|
||||
|
||||
### 3. Invariants
|
||||
|
||||
- **`StringMetaDataAttr.GetStringMetaData(object o)`**
|
||||
- Only inspects the *member name* derived from `o.ToString()`. For enums, this is the enum *name* (e.g., `"Red"`), not the value.
|
||||
- Returns `null` if `o` is `null`, or if `o.GetType().GetMember(...)` yields no results.
|
||||
- Does *not* search base types or interfaces—only the exact member named by `o.ToString()`.
|
||||
|
||||
- **`TrimTextBoxBehavior`**
|
||||
- Only trims on `LostFocus`; no trimming occurs during typing or on `TextChanged`.
|
||||
- Binding update is triggered via `UpdateSource()` only if trimming actually changed the text.
|
||||
|
||||
- **`InteractivityItems.Template`**
|
||||
- The `InteractivityTemplate.LoadContent()` must return a `FrameworkElement` containing `InteractivityItems` (or compatible structure); otherwise, behavior injection may fail silently.
|
||||
- `OnTemplateChanged` is invoked *after* the property is set; no guarantee about timing relative to visual tree load.
|
||||
|
||||
- **`TextBoxPasteBehavior`**
|
||||
- Only intercepts `Paste` if `PasteCommand` is set *before* paste occurs (via `PasteCommandChanged` subscription logic).
|
||||
- Assumes `sender` is either a `TextBox`, `ChannelCodeBuilder`, or `ChannelNameBuilder`; otherwise, `textBox` may be `null` (though `PasteCommandChanged` and `CommandExecuted` both attempt fallbacks).
|
||||
- `Clipboard.GetText()` may throw; exceptions are caught and published as `PageErrorEvent`.
|
||||
|
||||
- **`MultiSelectionBehavior`**
|
||||
- `SelectedItems` must be an `IList` (not `IEnumerable`) to support `Add`/`Remove`.
|
||||
- Type compatibility is checked via `type.IsAssignableFrom(item.GetType())`; items failing this are silently skipped (exception logged).
|
||||
- `_isUpdatingSource` and `_isUpdatingTarget` flags prevent infinite loops during bidirectional sync.
|
||||
- `SelectedItemsStatus.SetUpdating(...)` is used but *not defined in this module*—implies dependency on `DTS.Common.Utilities` (see *Dependencies*).
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependencies
|
||||
|
||||
#### Internal Dependencies (from imports)
|
||||
- **WPF Framework**:
|
||||
- `System.Windows`, `System.Windows.Controls`, `System.Windows.Interactivity` (for `Behavior<T>`, `Interaction`, `TriggerBase`).
|
||||
- `System.Windows.Input` (for `ICommand`, `RoutedEventHandler`, `ExecutedRoutedEventArgs`, `ApplicationCommands`).
|
||||
- **Prism Library**:
|
||||
- `Microsoft.Practices.Prism.Events` (`IEventAggregator`, `EventAggregator`).
|
||||
- `Microsoft.Practices.ServiceLocation` (`ServiceLocator`).
|
||||
- **Custom Types**:
|
||||
- `DTS.Common.Controls.ChannelCodeBuilder`, `DTS.Common.Controls.ChannelNameBuilder` (access `MainEditBox`).
|
||||
- `DTS.Common.Utilities.Logging.APILogger` (used in `MultiSelectionBehavior`).
|
||||
- `DTS.Common.Events.PageErrorEvent`, `PageErrorArg` (used in `TextBoxPasteBehavior`).
|
||||
- `DTS.Common.Utilities.SelectedItemsStatus` (used in `MultiSelectionBehavior` for `SetUpdating`).
|
||||
|
||||
#### External Dependencies
|
||||
- **Behavioral**:
|
||||
- `TrimTextBoxBehavior`, `MultiSelectionBehavior`, `InteractivityItems` require `System.Windows.Interactivity` (Blend SDK).
|
||||
- `TextBoxPasteBehavior` requires `System.Windows.Interactivity` indirectly via `Interaction` usage (though not directly instantiated here).
|
||||
|
||||
#### Consumers (inferred)
|
||||
- Likely used in XAML via `Interaction.Behaviors`, `InteractivityItems.Template`, or attached properties (`TextBoxPasteBehavior.PasteCommand`).
|
||||
- `StringMetaDataAttr` is likely applied to enums or classes in other modules (e.g., `enum Status { [StringMetaData("Active")] Active }`).
|
||||
|
||||
---
|
||||
|
||||
### 5. Gotchas
|
||||
|
||||
- **`StringMetaDataAttr.GetStringMetaData(object o)`**:
|
||||
- **Fails for enum *values* with `Flags` attribute** if `o.ToString()` returns a combined string (e.g., `"Red | Blue"`), as `GetMember("Red | Blue")` will not match any member.
|
||||
- **Does not handle nested types**—only top-level members named by `o.ToString()`.
|
||||
|
||||
- **`TrimTextBoxBehavior`**:
|
||||
- Trimming may cause caret position loss or unexpected selection changes (not mitigated).
|
||||
- `UpdateSource()` may trigger validation errors or other side effects in the binding pipeline.
|
||||
|
||||
- **`InteractivityItems.Template`**:
|
||||
- `OnTemplateChanged` assumes `interactivityTemplate.LoadContent()` returns an `InteractivityItems` instance. If not, casting to `(InteractivityItems)` will throw.
|
||||
- No deduplication: adding the same behavior/trigger multiple times via `Template` is possible.
|
||||
|
||||
- **`TextBoxPasteBehavior`**:
|
||||
- **Critical bug in `CommandExecuted`**:
|
||||
```csharp
|
||||
TextBox textBox = sender as TextBox;
|
||||
if (null == sender && sender is ChannelCodeBuilder ccb) // ← Always false: sender cannot be null *and* be a ChannelCodeBuilder
|
||||
```
|
||||
Should be `if (null == textBox && sender is ChannelCodeBuilder ccb)`. Same for `ChannelNameBuilder`. This will cause `textBox` to remain `null`, leading to `NullReferenceException` when accessing `textBox.RemoveHandler(...)` or `textBox.AddHandler(...)`.
|
||||
- `Clipboard.GetText()` may throw `ExternalException` (e.g., clipboard in use); caught but logged generically.
|
||||
|
||||
- **`MultiSelectionBehavior`**:
|
||||
- `SelectedItemsStatus.SetUpdating(...)` is used but *not defined in this module*—if `SelectedItemsStatus` is missing or misconfigured, notification suppression may fail, causing performance issues or infinite loops.
|
||||
- `itemsToAdd.Last()` check is inefficient for large lists (O(n) per item).
|
||||
- `selectedItems.Contains(item)` is O(n) per item; for large lists, this may be a performance bottleneck.
|
||||
- No handling of `NotifyCollectionChangedAction.Replace`—only `Add`, `Remove`, and `Reset`.
|
||||
|
||||
- **General**:
|
||||
- All behaviors assume WPF UI thread context (no dispatcher marshaling).
|
||||
- No null-safety for `AssociatedObject` in `OnDetaching`/`OnAttached` (relies on `Behavior<T>` base class to guard).
|
||||
- `StringMetaDataAttr` is `internal`—cannot be instantiated outside this module, limiting extensibility.
|
||||
|
||||
None identified beyond the above.
|
||||
Reference in New Issue
Block a user