260 lines
9.3 KiB
Plaintext
260 lines
9.3 KiB
Plaintext
|
|
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
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// IsLocked Attached Dependency Property
|
||
|
|
/// </summary>
|
||
|
|
public static readonly DependencyProperty IsLockedProperty =
|
||
|
|
DependencyProperty.RegisterAttached("IsLocked", typeof(Nullable<bool>), typeof(VirtualToggleButton),
|
||
|
|
new FrameworkPropertyMetadata((Nullable<bool>)false,
|
||
|
|
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,
|
||
|
|
new PropertyChangedCallback(OnIsLockedChanged)));
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Gets the IsLocked property. This dependency property
|
||
|
|
/// indicates whether the toggle button is checked.
|
||
|
|
/// </summary>
|
||
|
|
public static Nullable<bool> GetIsLocked(DependencyObject d)
|
||
|
|
{
|
||
|
|
return (Nullable<bool>)d.GetValue(IsLockedProperty);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Sets the IsLocked property. This dependency property
|
||
|
|
/// indicates whether the toggle button is checked.
|
||
|
|
/// </summary>
|
||
|
|
public static void SetIsLocked(DependencyObject d, Nullable<bool> value)
|
||
|
|
{
|
||
|
|
d.SetValue(IsLockedProperty, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Handles changes to the IsLocked property.
|
||
|
|
/// </summary>
|
||
|
|
private static void OnIsLockedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||
|
|
{
|
||
|
|
var pseudobutton = d as UIElement;
|
||
|
|
if (pseudobutton != null)
|
||
|
|
{
|
||
|
|
var newValue = (Nullable<bool>)e.NewValue;
|
||
|
|
if (newValue == true)
|
||
|
|
{
|
||
|
|
RaiseCheckedEvent(pseudobutton);
|
||
|
|
}
|
||
|
|
else if (newValue == false)
|
||
|
|
{
|
||
|
|
RaiseUncheckedEvent(pseudobutton);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
RaiseIndeterminateEvent(pseudobutton);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region IsThreeState
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// IsThreeState Attached Dependency Property
|
||
|
|
/// </summary>
|
||
|
|
public static readonly DependencyProperty IsThreeStateProperty =
|
||
|
|
DependencyProperty.RegisterAttached("IsThreeState", typeof(bool), typeof(VirtualToggleButton),
|
||
|
|
new FrameworkPropertyMetadata(false));
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 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.
|
||
|
|
/// </summary>
|
||
|
|
public static bool GetIsThreeState(DependencyObject d)
|
||
|
|
{
|
||
|
|
return (bool)d.GetValue(IsThreeStateProperty);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 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.
|
||
|
|
/// </summary>
|
||
|
|
public static void SetIsThreeState(DependencyObject d, bool value)
|
||
|
|
{
|
||
|
|
d.SetValue(IsThreeStateProperty, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region IsVirtualToggleButton
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// IsVirtualToggleButton Attached Dependency Property
|
||
|
|
/// </summary>
|
||
|
|
public static readonly DependencyProperty IsVirtualToggleButtonProperty =
|
||
|
|
DependencyProperty.RegisterAttached("IsVirtualToggleButton", typeof(bool), typeof(VirtualToggleButton),
|
||
|
|
new FrameworkPropertyMetadata(false,
|
||
|
|
new PropertyChangedCallback(OnIsVirtualToggleButtonChanged)));
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 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.
|
||
|
|
/// </summary>
|
||
|
|
public static bool GetIsVirtualToggleButton(DependencyObject d)
|
||
|
|
{
|
||
|
|
return (bool)d.GetValue(IsVirtualToggleButtonProperty);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 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.
|
||
|
|
/// </summary>
|
||
|
|
public static void SetIsVirtualToggleButton(DependencyObject d, bool value)
|
||
|
|
{
|
||
|
|
d.SetValue(IsVirtualToggleButtonProperty, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Handles changes to the IsVirtualToggleButton property.
|
||
|
|
/// </summary>
|
||
|
|
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
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// A static helper method to raise the Checked event on a target element.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="target">UIElement or ContentElement on which to raise the event</param>
|
||
|
|
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
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// A static helper method to raise the Unchecked event on a target element.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="target">UIElement or ContentElement on which to raise the event</param>
|
||
|
|
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
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// A static helper method to raise the Indeterminate event on a target element.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="target">UIElement or ContentElement on which to raise the event</param>
|
||
|
|
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<bool>)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
|
||
|
|
}
|
||
|
|
}
|