using System; using System.Windows; using System.Windows.Controls.Primitives; using System.Windows.Input; // ReSharper disable CheckNamespace namespace DTS.Viewer.GraphList { public static class VirtualToggleButton { #region attached properties #region IsLocked /// /// IsLocked Attached Dependency Property /// public static readonly DependencyProperty IsLockedProperty = DependencyProperty.RegisterAttached("IsLocked", typeof(Nullable), typeof(VirtualToggleButton), new FrameworkPropertyMetadata((Nullable)false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal, new PropertyChangedCallback(OnIsLockedChanged))); /// /// Gets the IsLocked property. This dependency property /// indicates whether the toggle button is checked. /// public static Nullable GetIsLocked(DependencyObject d) { return (Nullable)d.GetValue(IsLockedProperty); } /// /// Sets the IsLocked property. This dependency property /// indicates whether the toggle button is checked. /// public static void SetIsLocked(DependencyObject d, Nullable value) { d.SetValue(IsLockedProperty, value); } /// /// Handles changes to the IsLocked property. /// private static void OnIsLockedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var pseudobutton = d as UIElement; if (pseudobutton != null) { var newValue = (Nullable)e.NewValue; if (newValue == true) { RaiseCheckedEvent(pseudobutton); } else if (newValue == false) { RaiseUncheckedEvent(pseudobutton); } else { RaiseIndeterminateEvent(pseudobutton); } } } #endregion #region IsThreeState /// /// IsThreeState Attached Dependency Property /// public static readonly DependencyProperty IsThreeStateProperty = DependencyProperty.RegisterAttached("IsThreeState", typeof(bool), typeof(VirtualToggleButton), new FrameworkPropertyMetadata(false)); /// /// Gets the IsThreeState property. This dependency property /// indicates whether the control supports two or three states. /// IsLocked can be set to null as a third state when IsThreeState is true. /// public static bool GetIsThreeState(DependencyObject d) { return (bool)d.GetValue(IsThreeStateProperty); } /// /// Sets the IsThreeState property. This dependency property /// indicates whether the control supports two or three states. /// IsLocked can be set to null as a third state when IsThreeState is true. /// public static void SetIsThreeState(DependencyObject d, bool value) { d.SetValue(IsThreeStateProperty, value); } #endregion #region IsVirtualToggleButton /// /// IsVirtualToggleButton Attached Dependency Property /// public static readonly DependencyProperty IsVirtualToggleButtonProperty = DependencyProperty.RegisterAttached("IsVirtualToggleButton", typeof(bool), typeof(VirtualToggleButton), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsVirtualToggleButtonChanged))); /// /// Gets the IsVirtualToggleButton property. This dependency property /// indicates whether the object to which the property is attached is treated as a VirtualToggleButton. /// If true, the object will respond to keyboard and mouse input the same way a ToggleButton would. /// public static bool GetIsVirtualToggleButton(DependencyObject d) { return (bool)d.GetValue(IsVirtualToggleButtonProperty); } /// /// Sets the IsVirtualToggleButton property. This dependency property /// indicates whether the object to which the property is attached is treated as a VirtualToggleButton. /// If true, the object will respond to keyboard and mouse input the same way a ToggleButton would. /// public static void SetIsVirtualToggleButton(DependencyObject d, bool value) { d.SetValue(IsVirtualToggleButtonProperty, value); } /// /// Handles changes to the IsVirtualToggleButton property. /// private static void OnIsVirtualToggleButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var element = d as IInputElement; if (element != null) { if ((bool)e.NewValue) { element.MouseLeftButtonDown += OnMouseLeftButtonDown; element.KeyDown += OnKeyDown; } else { element.MouseLeftButtonDown -= OnMouseLeftButtonDown; element.KeyDown -= OnKeyDown; } } } #endregion #endregion #region routed events #region Checked /// /// A static helper method to raise the Checked event on a target element. /// /// UIElement or ContentElement on which to raise the event internal static RoutedEventArgs RaiseCheckedEvent(UIElement target) { if (target == null) return null; var args = new RoutedEventArgs { RoutedEvent = ToggleButton.CheckedEvent }; RaiseEvent(target, args); return args; } #endregion #region Unchecked /// /// A static helper method to raise the Unchecked event on a target element. /// /// UIElement or ContentElement on which to raise the event internal static RoutedEventArgs RaiseUncheckedEvent(UIElement target) { if (target == null) return null; var args = new RoutedEventArgs { RoutedEvent = ToggleButton.UncheckedEvent }; RaiseEvent(target, args); return args; } #endregion #region Indeterminate /// /// A static helper method to raise the Indeterminate event on a target element. /// /// UIElement or ContentElement on which to raise the event internal static RoutedEventArgs RaiseIndeterminateEvent(UIElement target) { if (target == null) return null; var args = new RoutedEventArgs { RoutedEvent = ToggleButton.IndeterminateEvent }; RaiseEvent(target, args); return args; } #endregion #endregion #region private methods private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { e.Handled = true; UpdateIsLocked(sender as DependencyObject); } private static void OnKeyDown(object sender, KeyEventArgs e) { if (e.OriginalSource == sender) { if (e.Key == Key.Space) { // ignore alt+space which invokes the system menu if ((Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt) return; UpdateIsLocked(sender as DependencyObject); e.Handled = true; } else if (e.Key == Key.Enter && (bool)(sender as DependencyObject).GetValue(KeyboardNavigation.AcceptsReturnProperty)) { UpdateIsLocked(sender as DependencyObject); e.Handled = true; } } } private static void UpdateIsLocked(DependencyObject d) { var IsLocked = GetIsLocked(d); if (IsLocked == true) { SetIsLocked(d, GetIsThreeState(d) ? null : (Nullable)false); } else { SetIsLocked(d, IsLocked.HasValue); } } private static void RaiseEvent(DependencyObject target, RoutedEventArgs args) { if (target is UIElement uiElement) { uiElement.RaiseEvent(args); } else if (target is ContentElement element) { element.RaiseEvent(args); } } #endregion } }