--- source_files: - DTS Viewer/DTS.Viewer.Modules/DTS.Viewer.GraphList/Classes/VirtualToggleButton.cs generated_at: "2026-04-16T13:48:16.790928+00:00" model: "zai-org/GLM-5-FP8" schema_version: 1 sha256: "001b39a3411ec3ba" --- # Documentation: VirtualToggleButton ## 1. Purpose `VirtualToggleButton` is a static helper class that provides attached dependency properties to imbue any WPF element with toggle button behavior. Rather than requiring inheritance from `ToggleButton`, this module allows arbitrary `DependencyObject` instances (specifically those implementing `IInputElement`) to respond to mouse clicks and keyboard input (Space/Enter) by toggling between checked, unchecked, and optionally indeterminate states. This is used within the `DTS.Viewer.GraphList` module to create toggle-style interactions on elements that cannot directly inherit from `ToggleButton`. --- ## 2. Public Interface ### Attached Properties #### `IsLockedProperty` - **Type:** `DependencyProperty` (attached) - **Value Type:** `Nullable` - **Default Value:** `false` - **Metadata Flags:** `BindsTwoWayByDefault | Journal` - **Get Accessor:** `Nullable GetIsLocked(DependencyObject d)` - **Set Accessor:** `void SetIsLocked(DependencyObject d, Nullable value)` - **Behavior:** Represents the toggle state. When changed, raises `ToggleButton.CheckedEvent` (if `true`), `ToggleButton.UncheckedEvent` (if `false`), or `ToggleButton.IndeterminateEvent` (if `null`). #### `IsThreeStateProperty` - **Type:** `DependencyProperty` (attached) - **Value Type:** `bool` - **Default Value:** `false` - **Get Accessor:** `bool GetIsThreeState(DependencyObject d)` - **Set Accessor:** `void SetIsThreeState(DependencyObject d, bool value)` - **Behavior:** When `true`, allows `IsLocked` to cycle through `null` (indeterminate) state during toggle operations. #### `IsVirtualToggleButtonProperty` - **Type:** `DependencyProperty` (attached) - **Value Type:** `bool` - **Default Value:** `false` - **Get Accessor:** `bool GetIsVirtualToggleButton(DependencyObject d)` - **Set Accessor:** `void SetIsVirtualToggleButton(DependencyObject d, bool value)` - **Behavior:** When set to `true` on an `IInputElement`, subscribes `OnMouseLeftButtonDown` and `OnKeyDown` handlers. When set to `false`, unsubscribes them. ### Internal Methods #### `RaiseCheckedEvent(UIElement target)` - **Returns:** `RoutedEventArgs` or `null` if target is null - **Behavior:** Raises `ToggleButton.CheckedEvent` on the target element. #### `RaiseUncheckedEvent(UIElement target)` - **Returns:** `RoutedEventArgs` or `null` if target is null - **Behavior:** Raises `ToggleButton.UncheckedEvent` on the target element. #### `RaiseIndeterminateEvent(UIElement target)` - **Returns:** `RoutedEventArgs` or `null` if target is null - **Behavior:** Raises `ToggleButton.IndeterminateEvent` on the target element. --- ## 3. Invariants 1. **Input Handler Attachment:** Setting `IsVirtualToggleButton` to `true` on a non-`IInputElement` has no effect (handlers are not attached, no exception is thrown). 2. **Toggle State Cycling Logic (in `UpdateIsLocked`):** - If `IsLocked == true`: Sets to `false`, or `null` if `IsThreeState` is `true`. - If `IsLocked == false` or `null`: Sets to `true`. 3. **Keyboard Handling:** - `Space` key toggles the state, unless `Alt` modifier is present (system menu invocation is preserved). - `Enter` key toggles the state only if `KeyboardNavigation.AcceptsReturnProperty` is `true` on the sender. 4. **Event Routing:** Raised events use `ToggleButton.CheckedEvent`, `ToggleButton.UncheckedEvent`, and `ToggleButton.IndeterminateEvent` as routed event identifiers. --- ## 4. Dependencies ### This Module Depends On: - `System` - `System.Windows` (`DependencyObject`, `DependencyProperty`, `FrameworkPropertyMetadata`, `UIElement`, `ContentElement`, `RoutedEventArgs`, `IInputElement`) - `System.Windows.Controls.Primitives` (`ToggleButton`) - `System.Windows.Input` (`Key`, `KeyEventArgs`, `Keyboard`, `KeyboardNavigation`, `ModifierKeys`, `MouseButtonEventArgs`) ### Consumers: - Unclear from source alone. The class is in `DTS.Viewer.GraphList` namespace, suggesting consumption by GraphList-related components. --- ## 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 `IsChecked` property. The property name `IsLocked` suggests a different semantic meaning (possibly "locked/selected" in the context of graph items). 2. **Type Inconsistency in Event Raising:** The private `RaiseEvent` method supports both `UIElement` and `ContentElement`, but the internal `RaiseCheckedEvent`, `RaiseUncheckedEvent`, and `RaiseIndeterminateEvent` methods only accept `UIElement`. If a `ContentElement` needs these events raised, the internal methods cannot be used directly. 3. **Namespace Suppression:** The file contains `// ReSharper disable CheckNamespace`, indicating the namespace `DTS.Viewer.GraphList` may not match the project's default namespace structure. This could indicate a refactoring artifact or intentional namespace override. 4. **No Null Guard in `UpdateIsLocked`:** The method casts `sender as DependencyObject` without null-checking before calling `GetIsLocked(d)`. If called with a non-`DependencyObject` sender, this would pass null to `GetIsLocked`, which would throw a `NullReferenceException` inside `d.GetValue()`. 5. **Event Handled Flag:** Both `OnMouseLeftButtonDown` and `OnKeyDown` mark events as `e.Handled = true`, which may prevent bubbling to parent handlers unexpectedly.