11 KiB
source_files, generated_at, model, schema_version, sha256
| source_files | generated_at | model | schema_version | sha256 | |||||
|---|---|---|---|---|---|---|---|---|---|
|
2026-04-16T02:15:57.710410+00:00 | Qwen/Qwen3-Coder-Next-FP8 | 1 | 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; setsMetaDatatoattr.public static string GetStringMetaData(object o)
Retrieves theMetaDatastring from aStringMetaDataAttrapplied to the enum value or type represented byo.- Uses reflection on
o.GetType().GetMember(o.ToString())to find the member. - Returns
nullif no attribute is found or ifoisnull/member not found.
- Uses reflection on
TrimTextBoxBehavior
public class TrimTextBoxBehavior : Behavior<TextBox>
Attaches to aTextBoxand trims itsTextproperty onLostFocus.- On attachment: subscribes to
LostFocus. - On
LostFocus: trimsText, updates binding source if changed. - On detachment: unsubscribes from
LostFocus.
- On attachment: subscribes to
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 aDependencyObject, loads content from theInteractivityTemplate, extracts its behaviors/triggers, and adds them to the target object’sInteraction.GetBehaviors()andInteraction.GetTriggers()collections.
TextBoxPasteBehavior
public static readonly DependencyProperty PasteCommandProperty
Attached dependency property forPasteCommand.public static ICommand GetPasteCommand(DependencyObject target)
Gets thePasteCommandvalue.public static void SetPasteCommand(DependencyObject target, ICommand value)
Sets thePasteCommandvalue.private static void PasteCommandChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
Attaches/detaches handler forCommandManager.ExecutedEventon the targetTextBox(or itsMainEditBoxifChannelCodeBuilder/ChannelNameBuilder).private static void CommandExecuted(object sender, RoutedEventArgs e)
HandlesApplicationCommands.Paste(or customRoutedUICommandnamed"Paste").- Retrieves text from
Clipboard. - Calls
command.Execute(textBox)ifcommand.CanExecute(null)is true. - Sets
e.Handled = trueto suppress default paste. - On exception, publishes
PageErrorEventviaIEventAggregator.
- Retrieves text from
MultiSelectionBehavior
public class MultiSelectionBehavior : Behavior<ListBox>
SynchronizesSelectedItemsof aListBoxwith an externalIList.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 toSelectedItems:- Clears
ListBox.SelectedItemsand repopulates from new value. - Subscribes/unsubscribes to
CollectionChangedon the new/old value andSelectionChangedonAssociatedObject.
- Clears
private void SourceCollectionChanged(...)
UpdatesAssociatedObject.SelectedItemswhen the externalIListchanges (e.g., viaINotifyCollectionChanged).private void ListBoxSelectionChanged(...)
Updates the externalSelectedItemslist whenListBoxselection changes.- Uses
SelectedItemsStatus.SetUpdating(...)to suppress notifications during bulk updates. - Skips adding items if already present.
- Logs exceptions via
APILogger.Log(ex).
- Uses
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
nullifoisnull, or ifo.GetType().GetMember(...)yields no results. - Does not search base types or interfaces—only the exact member named by
o.ToString().
- Only inspects the member name derived from
-
TrimTextBoxBehavior- Only trims on
LostFocus; no trimming occurs during typing or onTextChanged. - Binding update is triggered via
UpdateSource()only if trimming actually changed the text.
- Only trims on
-
InteractivityItems.Template- The
InteractivityTemplate.LoadContent()must return aFrameworkElementcontainingInteractivityItems(or compatible structure); otherwise, behavior injection may fail silently. OnTemplateChangedis invoked after the property is set; no guarantee about timing relative to visual tree load.
- The
-
TextBoxPasteBehavior- Only intercepts
PasteifPasteCommandis set before paste occurs (viaPasteCommandChangedsubscription logic). - Assumes
senderis either aTextBox,ChannelCodeBuilder, orChannelNameBuilder; otherwise,textBoxmay benull(thoughPasteCommandChangedandCommandExecutedboth attempt fallbacks). Clipboard.GetText()may throw; exceptions are caught and published asPageErrorEvent.
- Only intercepts
-
MultiSelectionBehaviorSelectedItemsmust be anIList(notIEnumerable) to supportAdd/Remove.- Type compatibility is checked via
type.IsAssignableFrom(item.GetType()); items failing this are silently skipped (exception logged). _isUpdatingSourceand_isUpdatingTargetflags prevent infinite loops during bidirectional sync.SelectedItemsStatus.SetUpdating(...)is used but not defined in this module—implies dependency onDTS.Common.Utilities(see Dependencies).
4. Dependencies
Internal Dependencies (from imports)
- WPF Framework:
System.Windows,System.Windows.Controls,System.Windows.Interactivity(forBehavior<T>,Interaction,TriggerBase).System.Windows.Input(forICommand,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(accessMainEditBox).DTS.Common.Utilities.Logging.APILogger(used inMultiSelectionBehavior).DTS.Common.Events.PageErrorEvent,PageErrorArg(used inTextBoxPasteBehavior).DTS.Common.Utilities.SelectedItemsStatus(used inMultiSelectionBehaviorforSetUpdating).
External Dependencies
- Behavioral:
TrimTextBoxBehavior,MultiSelectionBehavior,InteractivityItemsrequireSystem.Windows.Interactivity(Blend SDK).TextBoxPasteBehaviorrequiresSystem.Windows.Interactivityindirectly viaInteractionusage (though not directly instantiated here).
Consumers (inferred)
- Likely used in XAML via
Interaction.Behaviors,InteractivityItems.Template, or attached properties (TextBoxPasteBehavior.PasteCommand). StringMetaDataAttris 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
Flagsattribute ifo.ToString()returns a combined string (e.g.,"Red | Blue"), asGetMember("Red | Blue")will not match any member. - Does not handle nested types—only top-level members named by
o.ToString().
- Fails for enum values with
-
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:OnTemplateChangedassumesinteractivityTemplate.LoadContent()returns anInteractivityItemsinstance. If not, casting to(InteractivityItems)will throw.- No deduplication: adding the same behavior/trigger multiple times via
Templateis possible.
-
TextBoxPasteBehavior:- Critical bug in
CommandExecuted:Should beTextBox textBox = sender as TextBox; if (null == sender && sender is ChannelCodeBuilder ccb) // ← Always false: sender cannot be null *and* be a ChannelCodeBuilderif (null == textBox && sender is ChannelCodeBuilder ccb). Same forChannelNameBuilder. This will causetextBoxto remainnull, leading toNullReferenceExceptionwhen accessingtextBox.RemoveHandler(...)ortextBox.AddHandler(...). Clipboard.GetText()may throwExternalException(e.g., clipboard in use); caught but logged generically.
- Critical bug in
-
MultiSelectionBehavior:SelectedItemsStatus.SetUpdating(...)is used but not defined in this module—ifSelectedItemsStatusis 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—onlyAdd,Remove, andReset.
-
General:
- All behaviors assume WPF UI thread context (no dispatcher marshaling).
- No null-safety for
AssociatedObjectinOnDetaching/OnAttached(relies onBehavior<T>base class to guard). StringMetaDataAttrisinternal—cannot be instantiated outside this module, limiting extensibility.
None identified beyond the above.