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

5.8 KiB

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
DTS Viewer/DTS.Viewer.Modules/DTS.Viewer.GraphList/Classes/VirtualToggleButton.cs
2026-04-16T11:10:12.391241+00:00 zai-org/GLM-5-FP8 1 001b39a3411ec3ba

Documentation: VirtualToggleButton.cs

1. Purpose

VirtualToggleButton is a static utility class that provides attached dependency properties to imbue any WPF element with toggle button behavior without requiring inheritance from ToggleButton. It enables elements to respond to mouse clicks and keyboard input (Space/Enter) to toggle between checked/unchecked/indeterminate states, and raises the corresponding routed events. This is useful for templated controls or custom elements that need toggle semantics without the overhead of full ToggleButton derivation.


2. Public Interface

Attached Properties

Property Type Default Metadata Flags
IsLockedProperty Nullable<bool> false BindsTwoWayByDefault, Journal
IsThreeStateProperty bool false None
IsVirtualToggleButtonProperty bool false None

Public Methods

GetIsLocked(DependencyObject d) -> Nullable<bool>

Retrieves the current locked/checked state of the target element.

SetIsLocked(DependencyObject d, Nullable<bool> value)

Sets the locked/checked state. Setting to true raises ToggleButton.CheckedEvent; false raises ToggleButton.UncheckedEvent; null raises ToggleButton.IndeterminateEvent.

GetIsThreeState(DependencyObject d) -> bool

Returns whether the target supports three-state behavior (true/false/null).

SetIsThreeState(DependencyObject d, bool value)

Enables or disables three-state mode. When true, IsLocked can be set to null as a third state.

GetIsVirtualToggleButton(DependencyObject d) -> bool

Returns whether the target is currently acting as a virtual toggle button.

SetIsVirtualToggleButton(DependencyObject d, bool value)

When set to true, attaches MouseLeftButtonDown and KeyDown handlers to the target (must implement IInputElement). When set to false, detaches these handlers.

Internal Methods

RaiseCheckedEvent(UIElement target) -> RoutedEventArgs

Raises ToggleButton.CheckedEvent on the target element. Returns null if target is null.

RaiseUncheckedEvent(UIElement target) -> RoutedEventArgs

Raises ToggleButton.UncheckedEvent on the target element. Returns null if target is null.

RaiseIndeterminateEvent(UIElement target) -> RoutedEventArgs

Raises ToggleButton.IndeterminateEvent on the target element. Returns null if target is null.


3. Invariants

  1. Two-way binding by default: IsLockedProperty is registered with BindsTwoWayByDefault, so bindings will update the source automatically.

  2. Event attachment requirement: IsVirtualToggleButton only attaches event handlers if the target implements IInputElement. Non-IInputElement targets are silently ignored.

  3. Event raising requirement: RaiseEvent() only works for targets that are either UIElement or ContentElement. Other DependencyObject types will not raise events.

  4. Toggle cycle behavior:

    • When IsThreeState is false: toggles between true and false only.
    • When IsThreeState is true: cycles through falsetruenullfalse.
  5. Keyboard handling constraints:

    • Space key is ignored when Alt modifier is present (to avoid interfering with system menu).
    • Enter key only triggers toggle if KeyboardNavigation.AcceptsReturnProperty is true on the sender.
  6. Event source filtering: OnKeyDown only processes events where e.OriginalSource == sender, preventing handling of bubbled events from child elements.


4. Dependencies

This module depends on:

  • System (core types)
  • System.Windows (DependencyObject, DependencyProperty, FrameworkPropertyMetadata, UIElement, ContentElement, RoutedEventArgs, IInputElement)
  • System.Windows.Controls.Primitives (ToggleButton - for CheckedEvent, UncheckedEvent, IndeterminateEvent)
  • System.Windows.Input (Key, KeyEventArgs, Keyboard, KeyboardNavigation, ModifierKeys, MouseButtonEventArgs)

Consumers:

  • Unclear from source alone. Any XAML or code in the DTS.Viewer.GraphList namespace or referencing it may use these attached properties.

5. Gotchas

  1. Misleading XML documentation: The XML comments for IsLocked state "indicates whether the toggle button is checked" — this appears to be copy-pasted from a standard ToggleButton implementation. The property is named IsLocked, not IsChecked, which may indicate domain-specific semantics (e.g., locking a graph item vs. selecting it).

  2. Type mismatch between event raising methods: RaiseCheckedEvent, RaiseUncheckedEvent, and RaiseIndeterminateEvent accept only UIElement, but the private RaiseEvent helper supports both UIElement and ContentElement. If a ContentElement has IsLocked set, the change handler will attempt to raise events on it via RaiseEvent, but the public RaiseXxxEvent methods cannot be called with ContentElement directly.

  3. Null return from event methods: The RaiseXxxEvent methods return null when the target is null, but they do not throw. Callers should check for null if they intend to use the returned RoutedEventArgs.

  4. Local variable shadows property name: In UpdateIsLocked(), the local variable is named IsLocked, which shadows the property accessor method naming convention. This is legal but could cause confusion during debugging.

  5. No validation of IsThreeState consistency: Setting IsLocked to null is always possible regardless of IsThreeState value. The IsThreeState property only affects toggle behavior in UpdateIsLocked(), not direct programmatic assignment.