/************************************************************************************* Extended WPF Toolkit Copyright (C) 2007-2013 Xceed Software Inc. This program is provided to you under the terms of the Microsoft Public License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license For more features, controls, and fast professional support, pick up the Plus Edition at http://xceed.com/wpf_toolkit Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids ***********************************************************************************/ using System.Windows; using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Markup; namespace Xceed.Wpf.Toolkit { public enum Location { Left, Right } /// /// Represents a spinner control that includes two Buttons. /// [TemplatePart( Name = PART_IncreaseButton, Type = typeof( ButtonBase ) )] [TemplatePart( Name = PART_DecreaseButton, Type = typeof( ButtonBase ) )] [ContentProperty( "Content" )] public class ButtonSpinner : Spinner { private const string PART_IncreaseButton = "PART_IncreaseButton"; private const string PART_DecreaseButton = "PART_DecreaseButton"; #region Properties #region AllowSpin public static readonly DependencyProperty AllowSpinProperty = DependencyProperty.Register( "AllowSpin", typeof( bool ), typeof( ButtonSpinner ), new UIPropertyMetadata( true, AllowSpinPropertyChanged ) ); public bool AllowSpin { get { return ( bool )GetValue( AllowSpinProperty ); } set { SetValue( AllowSpinProperty, value ); } } private static void AllowSpinPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ButtonSpinner source = d as ButtonSpinner; source.OnAllowSpinChanged( (bool)e.OldValue, (bool)e.NewValue ); } #endregion //AllowSpin #region ButtonSpinnerLocation public static readonly DependencyProperty ButtonSpinnerLocationProperty = DependencyProperty.Register( "ButtonSpinnerLocation", typeof( Location ), typeof( ButtonSpinner ), new UIPropertyMetadata( Location.Right ) ); public Location ButtonSpinnerLocation { get { return ( Location )GetValue( ButtonSpinnerLocationProperty ); } set { SetValue( ButtonSpinnerLocationProperty, value ); } } #endregion //ButtonSpinnerLocation #region Content /// /// Identifies the Content dependency property. /// public static readonly DependencyProperty ContentProperty = DependencyProperty.Register( "Content", typeof( object ), typeof( ButtonSpinner ), new PropertyMetadata( null, OnContentPropertyChanged ) ); public object Content { get { return GetValue( ContentProperty ) as object; } set { SetValue( ContentProperty, value ); } } /// /// ContentProperty property changed handler. /// /// ButtonSpinner that changed its Content. /// Event arguments. private static void OnContentPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ButtonSpinner source = d as ButtonSpinner; source.OnContentChanged( e.OldValue, e.NewValue ); } #endregion //Content #region DecreaseButton private ButtonBase _decreaseButton; /// /// Gets or sets the DecreaseButton template part. /// private ButtonBase DecreaseButton { get { return _decreaseButton; } set { if( _decreaseButton != null ) { _decreaseButton.Click -= OnButtonClick; } _decreaseButton = value; if( _decreaseButton != null ) { _decreaseButton.Click += OnButtonClick; } } } #endregion //DecreaseButton #region IncreaseButton private ButtonBase _increaseButton; /// /// Gets or sets the IncreaseButton template part. /// private ButtonBase IncreaseButton { get { return _increaseButton; } set { if( _increaseButton != null ) { _increaseButton.Click -= OnButtonClick; } _increaseButton = value; if( _increaseButton != null ) { _increaseButton.Click += OnButtonClick; } } } #endregion //IncreaseButton #region ShowButtonSpinner public static readonly DependencyProperty ShowButtonSpinnerProperty = DependencyProperty.Register( "ShowButtonSpinner", typeof( bool ), typeof( ButtonSpinner ), new UIPropertyMetadata( true ) ); public bool ShowButtonSpinner { get { return ( bool )GetValue( ShowButtonSpinnerProperty ); } set { SetValue( ShowButtonSpinnerProperty, value ); } } #endregion //ShowButtonSpinner #endregion //Properties #region Constructors static ButtonSpinner() { DefaultStyleKeyProperty.OverrideMetadata( typeof( ButtonSpinner ), new FrameworkPropertyMetadata( typeof( ButtonSpinner ) ) ); } #endregion //Constructors #region Base Class Overrides public override void OnApplyTemplate() { base.OnApplyTemplate(); IncreaseButton = GetTemplateChild( PART_IncreaseButton ) as ButtonBase; DecreaseButton = GetTemplateChild( PART_DecreaseButton ) as ButtonBase; SetButtonUsage(); } /// /// Cancel LeftMouseButtonUp events originating from a button that has /// been changed to disabled. /// /// The data for the event. protected override void OnMouseLeftButtonUp( MouseButtonEventArgs e ) { base.OnMouseLeftButtonUp( e ); Point mousePosition; if( IncreaseButton != null && IncreaseButton.IsEnabled == false ) { mousePosition = e.GetPosition( IncreaseButton ); if( mousePosition.X > 0 && mousePosition.X < IncreaseButton.ActualWidth && mousePosition.Y > 0 && mousePosition.Y < IncreaseButton.ActualHeight ) { e.Handled = true; } } if( DecreaseButton != null && DecreaseButton.IsEnabled == false ) { mousePosition = e.GetPosition( DecreaseButton ); if( mousePosition.X > 0 && mousePosition.X < DecreaseButton.ActualWidth && mousePosition.Y > 0 && mousePosition.Y < DecreaseButton.ActualHeight ) { e.Handled = true; } } } protected override void OnPreviewKeyDown( KeyEventArgs e ) { switch( e.Key ) { case Key.Up: { if( this.AllowSpin ) { this.OnSpin( new SpinEventArgs( SpinDirection.Increase ) ); e.Handled = true; } break; } case Key.Down: { if( this.AllowSpin ) { this.OnSpin( new SpinEventArgs( SpinDirection.Decrease ) ); e.Handled = true; } break; } case Key.Enter: { //Do not Spin on enter Key when spinners have focus if( this.IncreaseButton.IsFocused || this.DecreaseButton.IsFocused ) { e.Handled = true; } break; } } } protected override void OnMouseWheel( MouseWheelEventArgs e ) { base.OnMouseWheel( e ); if( this.IsKeyboardFocusWithin && !e.Handled && this.AllowSpin ) { if( e.Delta < 0 ) { this.OnSpin( new SpinEventArgs( SpinDirection.Decrease, true ) ); } else if( 0 < e.Delta ) { this.OnSpin( new SpinEventArgs( SpinDirection.Increase, true ) ); } e.Handled = true; } } /// /// Called when valid spin direction changed. /// /// The old value. /// The new value. protected override void OnValidSpinDirectionChanged( ValidSpinDirections oldValue, ValidSpinDirections newValue ) { SetButtonUsage(); } #endregion //Base Class Overrides #region Event Handlers /// /// Handle click event of IncreaseButton and DecreaseButton template parts, /// translating Click to appropriate Spin event. /// /// Event sender, should be either IncreaseButton or DecreaseButton template part. /// Event args. private void OnButtonClick( object sender, RoutedEventArgs e ) { if( AllowSpin ) { SpinDirection direction = sender == IncreaseButton ? SpinDirection.Increase : SpinDirection.Decrease; OnSpin( new SpinEventArgs( direction ) ); } } #endregion //Event Handlers #region Methods /// /// Occurs when the Content property value changed. /// /// The old value of the Content property. /// The new value of the Content property. protected virtual void OnContentChanged( object oldValue, object newValue ) { } protected virtual void OnAllowSpinChanged( bool oldValue, bool newValue ) { SetButtonUsage(); } /// /// Disables or enables the buttons based on the valid spin direction. /// private void SetButtonUsage() { // buttonspinner adds buttons that spin, so disable accordingly. if( IncreaseButton != null ) { IncreaseButton.IsEnabled = AllowSpin && ( ( ValidSpinDirection & ValidSpinDirections.Increase ) == ValidSpinDirections.Increase ); } if( DecreaseButton != null ) { DecreaseButton.IsEnabled = AllowSpin && ( ( ValidSpinDirection & ValidSpinDirections.Decrease ) == ValidSpinDirections.Decrease ); } } #endregion //Methods } }