| File: System\Windows\Controls\Primitives\ToggleButton.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; using System.Windows.Threading; using System.Windows.Automation.Peers; using MS.Internal.KnownBoxes; namespace System.Windows.Controls.Primitives { /// <summary> /// ToggleButton /// </summary> [DefaultEvent("Checked")] public class ToggleButton : ButtonBase { #region Constructors static ToggleButton() { DefaultStyleKeyProperty.OverrideMetadata(typeof(ToggleButton), new FrameworkPropertyMetadata(typeof(ToggleButton))); _dType = DependencyObjectType.FromSystemTypeInternal(typeof(ToggleButton)); } /// <summary> /// Default ToggleButton constructor /// </summary> /// <remarks> /// Automatic determination of current Dispatcher. Use alternative constructor /// that accepts a Dispatcher for best performance. /// </remarks> public ToggleButton() : base() { } #endregion #region Properties and Events /// <summary> /// Checked event /// </summary> public static readonly RoutedEvent CheckedEvent = EventManager.RegisterRoutedEvent("Checked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ToggleButton)); /// <summary> /// Unchecked event /// </summary> public static readonly RoutedEvent UncheckedEvent = EventManager.RegisterRoutedEvent("Unchecked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ToggleButton)); /// <summary> /// Indeterminate event /// </summary> public static readonly RoutedEvent IndeterminateEvent = EventManager.RegisterRoutedEvent("Indeterminate", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ToggleButton)); /// <summary> /// Add / Remove Checked handler /// </summary> [Category("Behavior")] public event RoutedEventHandler Checked { add { AddHandler(CheckedEvent, value); } remove { RemoveHandler(CheckedEvent, value); } } /// <summary> /// Add / Remove Unchecked handler /// </summary> [Category("Behavior")] public event RoutedEventHandler Unchecked { add { AddHandler(UncheckedEvent, value); } remove { RemoveHandler(UncheckedEvent, value); } } /// <summary> /// Add / Remove Indeterminate handler /// </summary> [Category("Behavior")] public event RoutedEventHandler Indeterminate { add { AddHandler(IndeterminateEvent, value); } remove { RemoveHandler(IndeterminateEvent, value); } } /// <summary> /// The DependencyProperty for the IsChecked property. /// Flags: BindsTwoWayByDefault /// Default Value: false /// </summary> public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register( "IsChecked", typeof(bool?), typeof(ToggleButton), new FrameworkPropertyMetadata( BooleanBoxes.FalseBox, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal, new PropertyChangedCallback(OnIsCheckedChanged))); /// <summary> /// Indicates whether the ToggleButton is checked /// </summary> [Category("Appearance")] [TypeConverter(typeof(NullableBoolConverter))] [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] public bool? IsChecked { get { // Because Nullable<bool> unboxing is very slow (uses reflection) first we cast to bool object value = GetValue(IsCheckedProperty); if (value == null) return new Nullable<bool>(); else return new Nullable<bool>((bool)value); } set { SetValue(IsCheckedProperty, value.HasValue ? BooleanBoxes.Box(value.Value) : null); } } private static object OnGetIsChecked(DependencyObject d) {return ((ToggleButton)d).IsChecked;} /// <summary> /// Called when IsChecked is changed on "d." /// </summary> /// <param name="d">The object on which the property was changed.</param> /// <param name="e">EventArgs that contains the old and new values for this property</param> private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ToggleButton button = (ToggleButton)d; bool? oldValue = (bool?) e.OldValue; bool? newValue = (bool?) e.NewValue; //doing soft casting here because the peer can be that of RadioButton and it is not derived from //ToggleButtonAutomationPeer - specifically to avoid implementing TogglePattern ToggleButtonAutomationPeer peer = UIElementAutomationPeer.FromElement(button) as ToggleButtonAutomationPeer; peer?.RaiseToggleStatePropertyChangedEvent(oldValue, newValue); if (newValue == true) { button.OnChecked(new RoutedEventArgs(CheckedEvent)); } else if (newValue == false) { button.OnUnchecked(new RoutedEventArgs(UncheckedEvent)); } else { button.OnIndeterminate(new RoutedEventArgs(IndeterminateEvent)); } button.UpdateVisualState(); } /// <summary> /// Called when IsChecked becomes true. /// </summary> /// <param name="e">Event arguments for the routed event that is raised by the default implementation of this method.</param> protected virtual void OnChecked(RoutedEventArgs e) { RaiseEvent(e); } /// <summary> /// Called when IsChecked becomes false. /// </summary> /// <param name="e">Event arguments for the routed event that is raised by the default implementation of this method.</param> protected virtual void OnUnchecked(RoutedEventArgs e) { RaiseEvent(e); } /// <summary> /// Called when IsChecked becomes null. /// </summary> /// <param name="e">Event arguments for the routed event that is raised by the default implementation of this method.</param> protected virtual void OnIndeterminate(RoutedEventArgs e) { RaiseEvent(e); } /// <summary> /// The DependencyProperty for the IsThreeState property. /// Flags: None /// Default Value: false /// </summary> public static readonly DependencyProperty IsThreeStateProperty = DependencyProperty.Register( "IsThreeState", typeof(bool), typeof(ToggleButton), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); /// <summary> /// The IsThreeState property determines whether the control supports two or three states. /// IsChecked property can be set to null as a third state when IsThreeState is true /// </summary> [Bindable(true), Category("Behavior")] public bool IsThreeState { get { return (bool) GetValue(IsThreeStateProperty); } set { SetValue(IsThreeStateProperty, BooleanBoxes.Box(value)); } } #endregion #region Override methods /// <summary> /// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>) /// </summary> protected override AutomationPeer OnCreateAutomationPeer() { return new ToggleButtonAutomationPeer(this); } /// <summary> /// This override method is called when the control is clicked by mouse or keyboard /// </summary> protected override void OnClick() { OnToggle(); base.OnClick(); } #endregion #region Method Overrides internal override void ChangeVisualState(bool useTransitions) { base.ChangeVisualState(useTransitions); // Update the Check state group var isChecked = IsChecked; if (isChecked == true) { VisualStateManager.GoToState(this, VisualStates.StateChecked, useTransitions); } else if (isChecked == false) { VisualStateManager.GoToState(this, VisualStates.StateUnchecked, useTransitions); } else { // isChecked is null VisualStates.GoToState(this, useTransitions, VisualStates.StateIndeterminate, VisualStates.StateUnchecked); } } /// <summary> /// Gives a string representation of this object. /// </summary> public override string ToString() { string typeText = this.GetType().ToString(); string contentText = String.Empty; bool? isChecked = false; bool valuesDefined = false; // Accessing ToggleButton properties may be thread sensitive if (CheckAccess()) { contentText = GetPlainText(); isChecked = IsChecked; valuesDefined = true; } else { //Not on dispatcher, try posting to the dispatcher with 20ms timeout Dispatcher.Invoke(DispatcherPriority.Send, new TimeSpan(0, 0, 0, 0, 20), new DispatcherOperationCallback(delegate(object o) { contentText = GetPlainText(); isChecked = IsChecked; valuesDefined = true; return null; }), null); } // If Content and isChecked are defined if (valuesDefined) { return SR.Format(SR.ToStringFormatString_ToggleButton, typeText, contentText, isChecked.HasValue ? isChecked.Value.ToString() : "null"); } // Not able to access the dispatcher return typeText; } #endregion #region Protected virtual methods /// <summary> /// This vitrual method is called from OnClick(). ToggleButton toggles IsChecked property. /// Subclasses can override this method to implement their own toggle behavior /// </summary> protected internal virtual void OnToggle() { // If IsChecked == true && IsThreeState == true ---> IsChecked = null // If IsChecked == true && IsThreeState == false ---> IsChecked = false // If IsChecked == false ---> IsChecked = true // If IsChecked == null ---> IsChecked = false bool? isChecked; if (IsChecked == true) isChecked = IsThreeState ? (bool?)null : (bool?)false; else // false or null isChecked = IsChecked.HasValue; // HasValue returns true if IsChecked==false SetCurrentValueInternal(IsCheckedProperty, isChecked); } #endregion #region Data #endregion #region Accessibility #endregion #region DTypeThemeStyleKey // Returns the DependencyObjectType for the registered ThemeStyleKey's default // value. Controls will override this method to return approriate types. internal override DependencyObjectType DTypeThemeStyleKey { get { return _dType; } } private static DependencyObjectType _dType; #endregion DTypeThemeStyleKey } }