ButtonBase.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / Primitives / ButtonBase.cs / 1305600 / ButtonBase.cs

                            using System; 
using System.Collections;
using System.ComponentModel;
using System.Windows.Threading;
using System.Windows.Automation; 
using System.Windows.Automation.Provider;
using System.Windows.Controls; 
using System.Windows.Controls.Primitives; 
using System.Windows;
using System.Windows.Input; 
using System.Windows.Media;
using MS.Utility;
using MS.Internal.KnownBoxes;
using MS.Internal.PresentationFramework; 
using System.Diagnostics;
using System.Security; 
using System.Security.Permissions; 

namespace System.Windows.Controls.Primitives 
{
    /// 
    ///     The base class for all buttons
    ///  
    /// 
    ///     ButtonBase adds IsPressed state, Click event, and Invoke features to a ContentControl. 
    ///  
    [DefaultEvent("Click")]
    [Localizability(LocalizationCategory.Button)] 
    public abstract class ButtonBase : ContentControl, ICommandSource
    {
        #region Constructors
 
        static ButtonBase()
        { 
            EventManager.RegisterClassHandler(typeof(ButtonBase), AccessKeyManager.AccessKeyPressedEvent, new AccessKeyPressedEventHandler(OnAccessKeyPressed)); 
            KeyboardNavigation.AcceptsReturnProperty.OverrideMetadata(typeof(ButtonBase), new FrameworkPropertyMetadata(BooleanBoxes.TrueBox));
 
            // Disable IME on button.
            //  - key typing should not be eaten by IME.
            //  - when the button has a focus, IME's disabled status should be indicated as
            //    grayed buttons on the language bar. 
            InputMethod.IsInputMethodEnabledProperty.OverrideMetadata(typeof(ButtonBase), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits));
 
            IsMouseOverPropertyKey.OverrideMetadata(typeof(ButtonBase), new UIPropertyMetadata(new PropertyChangedCallback(OnVisualStatePropertyChanged))); 
            IsEnabledProperty.OverrideMetadata(typeof(ButtonBase), new UIPropertyMetadata(new PropertyChangedCallback(OnVisualStatePropertyChanged)));
        } 

        /// 
        ///     Default ButtonBase constructor
        ///  
        /// 
        ///     Automatic determination of current Dispatcher. Use alternative constructor 
        ///     that accepts a Dispatcher for best performance. 
        /// 
        protected ButtonBase() 
            : base()
        {
        }
 
        #endregion
 
        #region Virtual methods 
        /// 
        /// This virtual method is called when button is clicked and it raises the Click event 
        /// 
        protected virtual void OnClick()
        {
            RoutedEventArgs newEvent = new RoutedEventArgs(ButtonBase.ClickEvent, this); 
            RaiseEvent(newEvent);
 
            MS.Internal.Commands.CommandHelpers.ExecuteCommandSource(this); 
        }
 

        /// 
        ///     This method is invoked when the IsPressed property changes.
        ///  
        /// DependencyPropertyChangedEventArgs.
        protected virtual void OnIsPressedChanged(DependencyPropertyChangedEventArgs e) 
        { 
            OnVisualStatePropertyChanged(this, e);
        } 

        #endregion Virtual methods

        #region Private helpers 

        private bool IsInMainFocusScope 
        { 
            get
            { 
                Visual focusScope = FocusManager.GetFocusScope(this) as Visual;
                return focusScope == null || VisualTreeHelper.GetParent(focusScope) == null;
            }
        } 

        ///  
        /// This method is called when button is clicked via IInvokeProvider. 
        /// 
        internal void AutomationButtonBaseClick() 
        {
            OnClick();
        }
 
        private static bool IsValidClickMode(object o)
        { 
            ClickMode value = (ClickMode)o; 
            return value == ClickMode.Press
                || value == ClickMode.Release 
                || value == ClickMode.Hover;
        }

        ///  
        /// Override for 
        ///  
        protected internal override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) 
        {
            base.OnRenderSizeChanged(sizeInfo); 

            // *** Workaround ***
            // We need OnMouseRealyOver Property here
            // 
            // There is a problem when Button is capturing the Mouse and resizing untill the mouse fall of the Button
            // During that time, Button and Mouse didn't really move. However, we need to update the IsPressed property 
            // because mouse is no longer over the button. 
            // We migth need a new property called *** IsMouseReallyOver *** property, so we can update IsPressed when
            // it's changed. (Can't use IsMouseOver or IsMouseDirectlyOver 'coz once Mouse is captured, they're alway 'true'. 
            //

            // Update IsPressed property
            if (IsMouseCaptured && (Mouse.PrimaryDevice.LeftButton == MouseButtonState.Pressed) && !IsSpaceKeyDown) 
            {
                // At this point, RenderSize is not updated. We must use finalSize instead. 
                UpdateIsPressed(); 
            }
        } 

        /// 
        ///     Called when IsPressedProperty is changed on "d."
        ///  
        private static void OnIsPressedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            ButtonBase ctrl = (ButtonBase)d; 
            ctrl.OnIsPressedChanged(e);
        } 

        private static void OnAccessKeyPressed(object sender, AccessKeyPressedEventArgs e)
        {
            if (!e.Handled && e.Scope == null && e.Target == null) 
            {
                e.Target = (UIElement)sender; 
            } 
        }
 
        private void UpdateIsPressed()
        {
            Point pos = Mouse.PrimaryDevice.GetPosition(this);
 
            if ((pos.X >= 0) && (pos.X <= ActualWidth) && (pos.Y >= 0) && (pos.Y <= ActualHeight))
            { 
                if (!IsPressed) 
                {
                    SetIsPressed(true); 
                }
            }
            else if (IsPressed)
            { 
                SetIsPressed(false);
            } 
        } 

        #endregion Private helpers 

        #region Properties and Events
        /// 
        /// Event correspond to left mouse button click 
        /// 
        public static readonly RoutedEvent ClickEvent = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ButtonBase)); 
 
        /// 
        /// Add / Remove ClickEvent handler 
        /// 
        [Category("Behavior")]
        public event RoutedEventHandler Click { add { AddHandler(ClickEvent, value); } remove { RemoveHandler(ClickEvent, value); } }
 
        /// 
        ///     The DependencyProperty for RoutedCommand 
        ///  
        [CommonDependencyProperty]
        public static readonly DependencyProperty CommandProperty = 
                DependencyProperty.Register(
                        "Command",
                        typeof(ICommand),
                        typeof(ButtonBase), 
                        new FrameworkPropertyMetadata((ICommand)null,
                            new PropertyChangedCallback(OnCommandChanged))); 
 
        /// 
        /// The DependencyProperty for the CommandParameter 
        /// 
        [CommonDependencyProperty]
        public static readonly DependencyProperty CommandParameterProperty =
                DependencyProperty.Register( 
                        "CommandParameter",
                        typeof(object), 
                        typeof(ButtonBase), 
                        new FrameworkPropertyMetadata((object) null));
 
        /// 
        ///     The DependencyProperty for Target property
        ///     Flags:              None
        ///     Default Value:      null 
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty CommandTargetProperty = 
                DependencyProperty.Register(
                        "CommandTarget", 
                        typeof(IInputElement),
                        typeof(ButtonBase),
                        new FrameworkPropertyMetadata((IInputElement)null));
 
        /// 
        ///     The key needed set a read-only property. 
        ///  
        internal static readonly DependencyPropertyKey IsPressedPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "IsPressed",
                        typeof(bool),
                        typeof(ButtonBase),
                        new FrameworkPropertyMetadata( 
                                BooleanBoxes.FalseBox,
                                new PropertyChangedCallback(OnIsPressedChanged))); 
 
        /// 
        ///     The DependencyProperty for the IsPressed property. 
        ///     Flags:              None
        ///     Default Value:      false
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty IsPressedProperty =
                IsPressedPropertyKey.DependencyProperty; 
 
        /// 
        ///     IsPressed is the state of a button indicates that left mouse button is pressed or space key is pressed over the button. 
        /// 
        [Browsable(false), Category("Appearance"), ReadOnly(true)]
        public bool IsPressed
        { 
            get { return (bool) GetValue(IsPressedProperty); }
            protected set { SetValue(IsPressedPropertyKey, BooleanBoxes.Box(value)); } 
        } 

        private void SetIsPressed(bool pressed) 
        {
            if (pressed)
            {
                SetValue(IsPressedPropertyKey, BooleanBoxes.Box(pressed)); 
            }
            else 
            { 
                ClearValue(IsPressedPropertyKey);
            } 
        }

        /// 
        /// Get or set the Command property 
        /// 
        [Bindable(true), Category("Action")] 
        [Localizability(LocalizationCategory.NeverLocalize)] 
        public ICommand Command
        { 
            get
            {
                return (ICommand) GetValue(CommandProperty);
            } 
            set
            { 
                SetValue(CommandProperty, value); 
            }
        } 

        private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ButtonBase b = (ButtonBase)d; 
            b.OnCommandChanged((ICommand)e.OldValue, (ICommand)e.NewValue);
        } 
 
        private void OnCommandChanged(ICommand oldCommand, ICommand newCommand)
        { 
            if (oldCommand != null)
            {
                UnhookCommand(oldCommand);
            } 
            if (newCommand != null)
            { 
                HookCommand(newCommand); 
            }
        } 

        private void UnhookCommand(ICommand command)
        {
            EventHandler handler = CanExecuteChangedHandler.GetValue(this); 
            if (handler != null)
            { 
                command.CanExecuteChanged -= handler; 
                CanExecuteChangedHandler.ClearValue(this);
            } 
            UpdateCanExecute();
        }

        private void HookCommand(ICommand command) 
        {
            EventHandler handler = new EventHandler(OnCanExecuteChanged); 
            CanExecuteChangedHandler.SetValue(this, handler); 
            command.CanExecuteChanged += handler;
            UpdateCanExecute(); 
        }

        private void OnCanExecuteChanged(object sender, EventArgs e)
        { 
            UpdateCanExecute();
        } 
 
        private void UpdateCanExecute()
        { 
            if (Command != null)
            {
                CanExecute = MS.Internal.Commands.CommandHelpers.CanExecuteCommandSource(this);
            } 
            else
            { 
                CanExecute = true; 
            }
        } 

        /// 
        ///     Fetches the value of the IsEnabled property
        ///  
        /// 
        ///     The reason this property is overridden is so that Button 
        ///     can infuse the value for CanExecute into it. 
        /// 
        protected override bool IsEnabledCore 
        {
            get
            {
                return base.IsEnabledCore && CanExecute; 
            }
        } 
 
        /// 
        /// Reflects the parameter to pass to the CommandProperty upon execution. 
        /// 
        [Bindable(true), Category("Action")]
        [Localizability(LocalizationCategory.NeverLocalize)]
        public object CommandParameter 
        {
            get 
            { 
                return GetValue(CommandParameterProperty);
            } 
            set
            {
                SetValue(CommandParameterProperty, value);
            } 
        }
 
        ///  
        ///     The target element on which to fire the command.
        ///  
        [Bindable(true), Category("Action")]
        public IInputElement CommandTarget
        {
            get 
            {
                return (IInputElement)GetValue(CommandTargetProperty); 
            } 
            set
            { 
                SetValue(CommandTargetProperty, value);
            }
        }
 
        /// 
        ///     The DependencyProperty for the ClickMode property. 
        ///     Flags:              None 
        ///     Default Value:      ClickMode.Release
        ///  
        public static readonly DependencyProperty ClickModeProperty =
                DependencyProperty.Register(
                        "ClickMode",
                        typeof(ClickMode), 
                        typeof(ButtonBase),
                        new FrameworkPropertyMetadata(ClickMode.Release), 
                        new ValidateValueCallback(IsValidClickMode)); 

 
        /// 
        ///     ClickMode specify when the Click event should fire
        /// 
        [Bindable(true), Category("Behavior")] 
        public ClickMode ClickMode
        { 
            get 
            {
                return (ClickMode) GetValue(ClickModeProperty); 
            }
            set
            {
                SetValue(ClickModeProperty, value); 
            }
        } 
 
        #endregion Properties and Events
 
        #region Override methods
        /// 
        /// This is the method that responds to the MouseButtonEvent event.
        ///  
        /// Event arguments
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) 
        { 
            // Ignore when in hover-click mode.
            if (ClickMode != ClickMode.Hover) 
            {
                e.Handled = true;

                // Always set focus on itself 
                // In case ButtonBase is inside a nested focus scope we should restore the focus OnLostMouseCapture
                Focus(); 
 
                // It is possible that the mouse state could have changed during all of
                // the call-outs that have happened so far. 
                if (e.ButtonState == MouseButtonState.Pressed)
                {
                    // Capture the mouse, and make sure we got it.
                    // WARNING: callout 
                    CaptureMouse();
                    if (IsMouseCaptured) 
                    { 
                        // Though we have already checked this state, our call to CaptureMouse
                        // could also end up changing the state, so we check it again. 
                        if (e.ButtonState == MouseButtonState.Pressed)
                        {
                            if (!IsPressed)
                            { 
                                SetIsPressed(true);
                            } 
                        } 
                        else
                        { 
                            // Release capture since we decided not to press the button.
                            ReleaseMouseCapture();
                        }
                    } 
                }
 
                if (ClickMode == ClickMode.Press) 
                {
                    bool exceptionThrown = true; 
                    try
                    {
                        OnClick();
                        exceptionThrown = false; 
                    }
                    finally 
                    { 
                        if (exceptionThrown)
                        { 
                            // Cleanup the buttonbase state
                            SetIsPressed(false);
                            ReleaseMouseCapture();
                        } 
                    }
                } 
            } 

            base.OnMouseLeftButtonDown(e); 
        }

        /// 
        /// This is the method that responds to the MouseButtonEvent event. 
        /// 
        /// Event arguments 
        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) 
        {
            // Ignore when in hover-click mode. 
            if (ClickMode != ClickMode.Hover)
            {
                e.Handled = true;
                bool shouldClick = !IsSpaceKeyDown && IsPressed && ClickMode == ClickMode.Release; 

                if (IsMouseCaptured && !IsSpaceKeyDown) 
                { 
                    ReleaseMouseCapture();
                } 

                if (shouldClick)
                {
                    OnClick(); 
                }
            } 
 
            base.OnMouseLeftButtonUp(e);
        } 

        /// 
        /// This is the method that responds to the MouseEvent event.
        ///  
        /// Event arguments
        protected override void OnMouseMove(MouseEventArgs e) 
        { 
            base.OnMouseMove(e);
            if ((ClickMode != ClickMode.Hover) && 
                ((IsMouseCaptured && (Mouse.PrimaryDevice.LeftButton == MouseButtonState.Pressed) && !IsSpaceKeyDown)))
            {
                UpdateIsPressed();
 
                e.Handled = true;
            } 
        } 

        ///  
        ///     Called when this element loses mouse capture.
        /// 
        /// 
        protected override void OnLostMouseCapture(MouseEventArgs e) 
        {
            base.OnLostMouseCapture(e); 
 
            if ((e.OriginalSource == this) && (ClickMode != ClickMode.Hover) && !IsSpaceKeyDown)
            { 
                // If we are inside a nested focus scope - we should restore the focus to the main focus scope
                // This will cover the scenarios like ToolBar buttons
                if (IsKeyboardFocused && !IsInMainFocusScope)
                    Keyboard.Focus(null); 

                // When we lose capture, the button should not look pressed anymore 
                // -- unless the spacebar is still down, in which case we are still pressed. 
                SetIsPressed(false);
            } 
        }

        /// 
        ///     An event reporting the mouse entered this element. 
        /// 
        /// Event arguments 
        protected override void OnMouseEnter(MouseEventArgs e) 
        {
            base.OnMouseEnter(e); 
            if (HandleIsMouseOverChanged())
            {
                e.Handled = true;
            } 
        }
 
        ///  
        ///     An event reporting the mouse left this element.
        ///  
        /// Event arguments
        protected override void OnMouseLeave(MouseEventArgs e)
        {
            base.OnMouseLeave(e); 
            if (HandleIsMouseOverChanged())
            { 
                e.Handled = true; 
            }
        } 

        /// 
        ///     An event reporting that the IsMouseOver property changed.
        ///  
        private bool HandleIsMouseOverChanged()
        { 
            if (ClickMode == ClickMode.Hover) 
            {
                if (IsMouseOver) 
                {
                    // Hovering over the button will click in the OnHover click mode
                    SetIsPressed(true);
                    OnClick(); 
                }
                else 
                { 
                    SetIsPressed(false);
                } 

                return true;
            }
 
            return false;
        } 
 
        /// 
        /// This is the method that responds to the KeyDown event. 
        /// 
        /// Event arguments
        protected override void OnKeyDown(KeyEventArgs e)
        { 
            base.OnKeyDown(e);
 
            if (ClickMode == ClickMode.Hover) 
            {
                // Ignore when in hover-click mode. 
                return;
            }

            if (e.Key == Key.Space) 
            {
                // Alt+Space should bring up system menu, we shouldn't handle it. 
                if ((Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Alt)) != ModifierKeys.Alt) 
                {
                    if ((!IsMouseCaptured) && (e.OriginalSource == this)) 
                    {
                        IsSpaceKeyDown = true;
                        SetIsPressed(true);
                        CaptureMouse(); 

                        if (ClickMode == ClickMode.Press) 
                        { 
                            OnClick();
                        } 

                        e.Handled = true;
                    }
                } 
            }
            else if (e.Key == Key.Enter && (bool)GetValue(KeyboardNavigation.AcceptsReturnProperty)) 
            { 
                if (e.OriginalSource == this)
                { 
                    IsSpaceKeyDown = false;
                    SetIsPressed(false);
                    if (IsMouseCaptured)
                    { 
                        ReleaseMouseCapture();
                    } 
 
                    OnClick();
                    e.Handled = true; 
                }
            }
            else
            { 
                // On any other key we set IsPressed to false only if Space key is pressed
                if (IsSpaceKeyDown) 
                { 
                    SetIsPressed(false);
                    IsSpaceKeyDown = false; 
                    if (IsMouseCaptured)
                    {
                        ReleaseMouseCapture();
                    } 
                }
            } 
        } 

        ///  
        /// This is the method that responds to the KeyUp event.
        /// 
        /// Event arguments
        protected override void OnKeyUp(KeyEventArgs e) 
        {
            base.OnKeyUp(e); 
 
            if (ClickMode == ClickMode.Hover)
            { 
                // Ignore when in hover-click mode.
                return;
            }
 
            if ((e.Key == Key.Space) && IsSpaceKeyDown)
            { 
                // Alt+Space should bring up system menu, we shouldn't handle it. 
                if ((Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Alt)) != ModifierKeys.Alt)
                { 
                    IsSpaceKeyDown = false;
                    if (GetMouseLeftButtonReleased())
                    {
                        bool shouldClick = IsPressed && ClickMode == ClickMode.Release; 

                        // Release mouse capture if left mouse button is not pressed 
                        if (IsMouseCaptured) 
                        {
                            // OnLostMouseCapture set IsPressed to false 
                            ReleaseMouseCapture();
                        }

                        if (shouldClick) 
                            OnClick();
                    } 
                    else 
                    {
                        // IsPressed state is updated only if mouse is captured (bugfix 919349) 
                        if (IsMouseCaptured)
                            UpdateIsPressed();
                    }
 
                    e.Handled = true;
                } 
            } 
        }
 
        /// 
        ///     An event announcing that the keyboard is no longer focused
        /// 
        /// Event arguments 
        protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
        { 
            base.OnLostKeyboardFocus(e); 

            if (ClickMode == ClickMode.Hover) 
            {
                // Ignore when in hover-click mode.
                return;
            } 

            if (e.OriginalSource == this) 
            { 
                if (IsPressed)
                { 
                    SetIsPressed(false);
                }

                if (IsMouseCaptured) 
                    ReleaseMouseCapture();
 
                IsSpaceKeyDown = false; 
            }
        } 

        /// 
        /// The Access key for this control was invoked.
        ///  
        protected override void OnAccessKey(AccessKeyEventArgs e)
        { 
            if (e.IsMultiple) 
            {
                base.OnAccessKey(e); 
            }
            else
            {
                // Don't call the base b/c we don't want to take focus 
                OnClick();
            } 
        } 

        ///  
        /// Critical - calling critical InputManager.Current
        /// Safe - InputManager.Current is not exposed and used temporary to determine the mouse state
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private bool GetMouseLeftButtonReleased()
        { 
            return InputManager.Current.PrimaryMouseDevice.LeftButton == MouseButtonState.Released; 
        }
 
        private bool IsSpaceKeyDown
        {
            get { return ReadControlFlag(ControlBoolFlags.IsSpaceKeyDown); }
            set { WriteControlFlag(ControlBoolFlags.IsSpaceKeyDown, value); } 
        }
 
        private bool CanExecute 
        {
            get { return !ReadControlFlag(ControlBoolFlags.CommandDisabled); } 
            set
            {
                if (value != CanExecute)
                { 
                    WriteControlFlag(ControlBoolFlags.CommandDisabled, !value);
                    CoerceValue(IsEnabledProperty); 
                } 
            }
        } 

        #endregion

        #region Visual State Manager 

        ///  
        ///     Change to the correct visual state for the ButtonBase. 
        /// 
        ///  
        ///     true to use transitions when updating the visual state, false to
        ///     snap directly to the new visual state.
        /// 
        internal override void ChangeVisualState(bool useTransitions) 
        {
            if (!IsEnabled) 
            { 
                VisualStateManager.GoToState(this, VisualStates.StateDisabled, useTransitions);
            } 
            else if (IsPressed)
            {
                VisualStateManager.GoToState(this, VisualStates.StatePressed, useTransitions);
            } 
            else if (IsMouseOver)
            { 
                VisualStateManager.GoToState(this, VisualStates.StateMouseOver, useTransitions); 
            }
            else 
            {
                VisualStateManager.GoToState(this, VisualStates.StateNormal, useTransitions);
            }
 
            if (IsKeyboardFocused)
            { 
                VisualStateManager.GoToState(this, VisualStates.StateFocused, useTransitions); 
            }
            else 
            {
                VisualStateManager.GoToState(this, VisualStates.StateUnfocused, useTransitions);
            }
 
            base.ChangeVisualState(useTransitions);
        } 
 
        #endregion
 
        #region Data

        private static readonly UncommonField CanExecuteChangedHandler = new UncommonField();
 
        #endregion
    } 
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK