ButtonBase.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Controls / Primitives / ButtonBase.cs / 1 / 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));
        } 
 
        /// 
        ///     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)
        { 
        }
 
        #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 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.
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));
        } 
 
        /// 
        ///     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)
        { 
        }
 
        #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 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