Files
DP44/enriched-partialglm/Common/DTS.CommonCore/Behaviors.md
2026-04-17 14:55:32 -04:00

9.5 KiB

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
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
2026-04-16T12:04:47.328170+00:00 zai-org/GLM-5-FP8 1 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.ControlsTextBox, ListBox, SelectionChangedEventArgs
  • System.Windows.InputICommand, CommandManager, ApplicationCommands, ExecutedRoutedEventArgs
  • DTS.Common.ControlsChannelCodeBuilder, ChannelNameBuilder (referenced in TextBoxPasteBehavior)
  • DTS.Common.EventsPageErrorEvent, PageErrorArg (used for error publishing)
  • DTS.Common.Enums — Referenced in MultiSelectionBehavior (likely contains SelectedItemsStatus)
  • DTS.Common.Utilities.LoggingAPILogger.Log() for exception logging
  • Microsoft.Practices.Prism.EventsIEventAggregator
  • Microsoft.Practices.ServiceLocationServiceLocator

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.