Files
2026-04-17 14:55:32 -04:00

9.8 KiB
Raw Permalink Blame History

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
Common/DTS.Common/Behaviors/StringMetaDataAttr.cs
Common/DTS.Common/Behaviors/TrimTextBoxBehavior.cs
Common/DTS.Common/Behaviors/InteractivityTemplate.cs
Common/DTS.Common/Behaviors/TextBoxPasteBehavior.cs
Common/DTS.Common/Behaviors/MultiSelectionBehavior.cs
2026-04-16T02:55:26.714339+00:00 Qwen/Qwen3-Coder-Next-FP8 1 13307045704efc6d

Behaviors

Documentation: DTS.Common.Behaviors Module


1. Purpose

This module provides a collection of WPF-specific behaviors and utility attributes to extend UI control functionality and metadata handling in the DTS application. It enables declarative attachment of common UI patterns—such as text trimming on TextBox controls, paste interception with custom command execution, and bidirectional synchronization of multi-selection state between a ListBox and an external IList—without requiring code-behind. Additionally, it offers a generic attribute (StringMetaDataAttr) for attaching string-based metadata to types or enum values via reflection, and a framework (InteractivityTemplate) for packaging and reusing collections of behaviors and triggers as reusable XAML templates.


2. Public Interface

StringMetaDataAttr

  • public string MetaData { get; }
    Immutable property storing the attached metadata string.
  • internal StringMetaDataAttr(string attr)
    Constructor (internal) to initialize MetaData.
  • public static string GetStringMetaData(object o)
    Retrieves the MetaData string from a StringMetaDataAttr applied to the member (field/property) corresponding to o.ToString() (e.g., for an enum value, looks up the enum field). Returns null if no attribute found or reflection fails.

TrimTextBoxBehavior

  • public class TrimTextBoxBehavior : Behavior<TextBox>
    Attaches to a TextBox and trims leading/trailing whitespace from its Text property on LostFocus. If trimming occurs, it updates the binding source.

InteractivityTemplate

  • public class InteractivityTemplate : DataTemplate
    A no-op subclass of DataTemplate, used as a marker type for XAML-based interactivity templates.
  • public class InteractivityItems : FrameworkElement
    Holds collections of Behaviors and TriggerBases. Exposes:
    • public List<TriggerBase> Triggers { get; }
      Lazy-initialized list for triggers.
    • public List<Behavior> Behaviors { get; }
      Lazy-initialized list for behaviors.
    • public static readonly DependencyProperty TemplateProperty
      Attached dependency property "Template" of type InteractivityTemplate.
    • public static InteractivityTemplate GetTemplate(DependencyObject obj) / SetTemplate(...)
      Accessors for the Template attached property. When set, loads the InteractivityTemplates content (expected to be an InteractivityItems instance), and copies its Behaviors and Triggers into the target object via Interaction.GetBehaviors(obj) and Interaction.GetTriggers(obj).

TextBoxPasteBehavior

  • public static readonly DependencyProperty PasteCommandProperty
    Attached dependency property for PasteCommand.
  • public static ICommand GetPasteCommand(DependencyObject target) / SetPasteCommand(...)
    Get/set the PasteCommand attached property.
  • Behavior:
    When PasteCommand is set on a TextBox, ChannelCodeBuilder, or ChannelNameBuilder (using their MainEditBox), it:
    • Subscribes to CommandManager.ExecutedEvent for Paste commands.
    • On paste execution, retrieves clipboard text (though not used in current implementation).
    • Invokes PasteCommand.Execute(textBox) if CanExecute(null) returns true.
    • Sets e.Handled = true to suppress default paste.
    • On error, publishes a PageErrorEvent via Prisms IEventAggregator.

MultiSelectionBehavior

  • public class MultiSelectionBehavior : Behavior<ListBox>
    Synchronizes selection state between a ListBox.SelectedItems and an external IList (typically ObservableCollection<T> or BulkObservableCollection<T>).
  • public IList SelectedItems { get; set; }
    Dependency property backing the external list to sync with.
  • Key behaviors:
    • On attach: Populates ListBox.SelectedItems from SelectedItems.
    • On SelectedItems property change:
      • Clears ListBox.SelectedItems, repopulates from new value.
      • Subscribes to CollectionChanged on the new value and SelectionChanged on the ListBox.
    • On ListBox.SelectionChanged: Updates SelectedItems (external list) with added/removed items.
      • Uses SelectedItemsStatus.SetUpdating(...) to suppress notifications during bulk updates.
      • Special handling for BulkObservableCollection<IAnalogSensor> and BulkObservableCollection<ITestSetup> via BulkOperations* methods to use AddRange/RemoveRange for efficiency.
    • On SelectedItems.CollectionChanged: Updates ListBox.SelectedItems.

3. Invariants

  • StringMetaDataAttr.GetStringMetaData(object o)

    • Only inspects the member named by o.ToString() (e.g., for MyEnum.ValueX, looks for MyEnum.ValueX field/property).
    • Returns null if o is null, member lookup fails, or attribute is absent.
    • Does not inspect attributes on the type of o, only its member.
  • TrimTextBoxBehavior

    • Only trims on LostFocus. Does not trim on input, typing, or GotFocus.
    • Only updates the binding source if the trimmed text differs from current text.
  • InteractivityItems.Template

    • The InteractivityTemplate.LoadContent() result must be an InteractivityItems instance (or compatible), otherwise casting fails.
    • Behavior/trigger addition is additive—does not clear existing behaviors/triggers on the target object.
  • TextBoxPasteBehavior

    • Only handles ApplicationCommands.Paste or a RoutedUICommand named "Paste".
    • Does not inspect or modify clipboard content—only invokes the bound PasteCommand with the TextBox as parameter.
    • Relies on ContainerLocator.Container being initialized (for IEventAggregator resolution); failure here may cause silent logging errors.
  • MultiSelectionBehavior

    • Requires SelectedItems to be an IList (not IEnumerable) and ideally INotifyCollectionChanged for two-way sync.
    • Uses SelectedItemsStatus.SetUpdating(...) to signal bulk operations—consumers must respect this flag to avoid spurious notifications.
    • Type-specific bulk operations (BulkOperations*) only apply when SelectedItems is a BulkObservableCollection<T> with T being IAnalogSensor or ITestSetup.
    • AddItems and RemoveItems methods perform null checks; exceptions during item addition are logged via APILogger.Log(ex) but do not halt processing.

4. Dependencies

Dependencies of this module:

  • WPF: System.Windows, System.Windows.Controls, System.Windows.Input, System.Windows.Interactivity (via Microsoft.Xaml.Behaviors).
  • Prism: Prism.Ioc, Prism.Events (IEventAggregator, ContainerLocator).
  • Domain types:
    • DTS.Common.Controls.ChannelCodeBuilder, ChannelNameBuilder (for MainEditBox).
    • DTS.Common.Interface.Sensors.SensorsList.IAnalogSensor, ITestSetup.
    • DTS.Common.Classes.BulkObservableCollection<T>.
    • DTS.Common.Enums, DTS.Common.Utilities.Logging.APILogger, SelectedItemsStatus.

Dependencies on this module:

  • Likely used by UI layers (e.g., XAML views) to attach behaviors declaratively.
  • InteractivityItems.Template is intended for use in XAML DataTemplates to share interactivity logic across controls.

5. Gotchas

  • StringMetaDataAttr.GetStringMetaData

    • Misleading name: Operates on members (e.g., enum fields), not the type of the object passed. Passing an enum value works, but passing a non-enum object (e.g., new MyClass()) will likely fail unless o.ToString() matches a member name.
    • Uses GetMember(o.ToString()), which is case-sensitive and may fail if ToString() is overridden unexpectedly.
  • TrimTextBoxBehavior

    • Does not handle TextChanged or validation—trimming happens only on LostFocus, which may cause UX surprises if binding updates are deferred.
  • InteractivityItems.Template

    • OnTemplateChanged assumes LoadContent() returns an InteractivityItems instance. If the XAML template is malformed or returns a different type, a runtime cast exception occurs.
  • TextBoxPasteBehavior

    • Clipboard text is retrieved (Clipboard.GetText()) but never used—the PasteCommand receives the TextBox as parameter, but the command implementation must handle clipboard content itself.
    • Uses ContainerLocator.Container (static), which may cause issues in test scenarios or if Prism container initialization is delayed.
  • MultiSelectionBehavior

    • Critical: The SelectedItems list must be mutable and support Add/Remove/Clear. If its read-only (e.g., IList wrapping an array), runtime exceptions occur.
    • Bulk operations (BulkOperations*) only trigger for exact type matches: BulkObservableCollection<IAnalogSensor> or BulkObservableCollection<ITestSetup>. Other generic instantiations (e.g., BulkObservableCollection<DerivedSensor>) fall back to per-item operations.
    • SelectedItemsStatus.SetUpdating(...) is used internally, but its implementation (SelectedItemsStatus class) is not provided in the source—consumers must ensure its correctly implemented to avoid infinite loops or missed updates.
  • General:

    • All behaviors assume WPFs Interaction service is available (via Microsoft.Xaml.Behaviors).
    • No explicit disposal/cleanup in MultiSelectionBehavior for event handlers beyond OnDetaching—re-attaching may cause duplicate subscriptions if not handled carefully.