Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / 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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- AspCompat.cs
- NotificationContext.cs
- TextElementEnumerator.cs
- Vector3DAnimationUsingKeyFrames.cs
- AddInController.cs
- MaskInputRejectedEventArgs.cs
- SystemIcmpV6Statistics.cs
- _SafeNetHandles.cs
- RSAPKCS1SignatureDeformatter.cs
- ExpressionContext.cs
- EventBuilder.cs
- LayoutTable.cs
- FontInfo.cs
- LazyTextWriterCreator.cs
- SR.cs
- Utility.cs
- CodeCompileUnit.cs
- _HelperAsyncResults.cs
- StringFunctions.cs
- TraceProvider.cs
- ListViewTableCell.cs
- QueryResponse.cs
- NativeConfigurationLoader.cs
- ValidatorCompatibilityHelper.cs
- WmlObjectListAdapter.cs
- SessionEndingEventArgs.cs
- QueueException.cs
- SqlDataSourceFilteringEventArgs.cs
- FormViewInsertedEventArgs.cs
- QilInvokeLateBound.cs
- PriorityBinding.cs
- GridViewUpdatedEventArgs.cs
- HttpListenerException.cs
- ColorContext.cs
- JoinTreeSlot.cs
- SafePEFileHandle.cs
- DocumentGrid.cs
- MonthCalendar.cs
- GlobalizationSection.cs
- RelatedImageListAttribute.cs
- WindowInteropHelper.cs
- RootBuilder.cs
- SqlGenericUtil.cs
- LocationSectionRecord.cs
- RoutedEvent.cs
- BoundPropertyEntry.cs
- ApplicationDirectoryMembershipCondition.cs
- _NetworkingPerfCounters.cs
- HandleDictionary.cs
- ConfigPathUtility.cs
- TreeViewAutomationPeer.cs
- LocalizabilityAttribute.cs
- BinaryObjectReader.cs
- HtmlInputSubmit.cs
- ClosureBinding.cs
- MergeFailedEvent.cs
- oledbmetadatacollectionnames.cs
- MetadataPropertyCollection.cs
- MarginCollapsingState.cs
- TextParagraphCache.cs
- BulletChrome.cs
- XmlNamespaceMappingCollection.cs
- FamilyTypeface.cs
- DesignDataSource.cs
- XPathSelectionIterator.cs
- ContractCodeDomInfo.cs
- AccessorTable.cs
- StrokeNodeOperations2.cs
- TypeConverterAttribute.cs
- PerspectiveCamera.cs
- EventProviderWriter.cs
- C14NUtil.cs
- ConfigXmlElement.cs
- HijriCalendar.cs
- CurrentChangedEventManager.cs
- ElementFactory.cs
- FragmentNavigationEventArgs.cs
- FontUnitConverter.cs
- GetParentChain.cs
- ConsumerConnectionPointCollection.cs
- ZoomPercentageConverter.cs
- SortKey.cs
- ConstructorNeedsTagAttribute.cs
- PrintingPermission.cs
- ToolTip.cs
- sitestring.cs
- InkSerializer.cs
- DataGridViewTopRowAccessibleObject.cs
- SiteMapHierarchicalDataSourceView.cs
- FixedLineResult.cs
- Util.cs
- ImageAnimator.cs
- DataGridParentRows.cs
- HttpRawResponse.cs
- NativeMethods.cs
- ReferenceSchema.cs
- CachedPathData.cs
- GifBitmapDecoder.cs
- COM2FontConverter.cs
- Int16Animation.cs