diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/InputBase.cs b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/InputBase.cs index f3ec5fdf..0b813db4 100644 --- a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/InputBase.cs +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/InputBase.cs @@ -21,23 +21,24 @@ namespace Microsoft.Windows.Controls.Primitives #region Text - public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(InputBase), new PropertyMetadata(default(String), OnTextPropertyChanged)); + public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(InputBase), new UIPropertyMetadata(default(String), OnTextChanged)); public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } - private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + private static void OnTextChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { - InputBase input = (InputBase)d; - input.OnTextChanged((string)e.OldValue, (string)e.NewValue); + InputBase inputBase = o as InputBase; + if (inputBase != null) + inputBase.OnTextChanged((string)e.OldValue, (string)e.NewValue); } - protected virtual void OnTextChanged(string previousValue, string currentValue) + protected virtual void OnTextChanged(string oldValue, string newValue) { - } + } #endregion //Text diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/UpDownBase.cs b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/UpDownBase.cs index ae415f7b..3f4c1a5e 100644 --- a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/UpDownBase.cs +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/UpDownBase.cs @@ -186,4 +186,268 @@ namespace Microsoft.Windows.Controls.Primitives #endregion //Methods } + + /// + /// This is going to be the new UpDownBase class. In order to reliably support the different numeric data types, I need to create a specific control for each data type. + /// So instead of copying and pasting I am going to try to create a generic base class that has most of the logic in it. This will make the NumericUpDown control obsolete + /// and it will be removed from the toolkit. The new controls will be DecimalUpDown, DoubleUpDown, and IntegerUpDown. + /// + /// + public abstract class UpDownBase : InputBase + { + #region Members + + /// + /// Name constant for Text template part. + /// + internal const string ElementTextName = "TextBox"; + + /// + /// Name constant for Spinner template part. + /// + internal const string ElementSpinnerName = "Spinner"; + + /// + /// Flags if the Text and Value properties are in the process of being sync'd + /// + private bool _isSyncingTextAndValueProperties; + + #endregion //Members + + #region Properties + + protected TextBox TextBox { get; private set; } + internal Spinner Spinner { get; private set; } + + #region AllowSpin + + public static readonly DependencyProperty AllowSpinProperty = DependencyProperty.Register("AllowSpin", typeof(bool), typeof(UpDownBase), new UIPropertyMetadata(true)); + public bool AllowSpin + { + get { return (bool)GetValue(AllowSpinProperty); } + set { SetValue(AllowSpinProperty, value); } + } + + #endregion //AllowSpin + + #region ShowButtonSpinner + + public static readonly DependencyProperty ShowButtonSpinnerProperty = DependencyProperty.Register("ShowButtonSpinner", typeof(bool), typeof(UpDownBase), new UIPropertyMetadata(true)); + public bool ShowButtonSpinner + { + get { return (bool)GetValue(ShowButtonSpinnerProperty); } + set { SetValue(ShowButtonSpinnerProperty, value); } + } + + #endregion //ShowButtonSpinner + + #region Value + + public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(T), typeof(UpDownBase), new UIPropertyMetadata(default(T), OnValueChanged, OnCoerceValue)); + public T Value + { + get { return (T)GetValue(ValueProperty); } + set { SetValue(ValueProperty, value); } + } + + private static object OnCoerceValue(DependencyObject o, object value) + { + UpDownBase upDownBase = o as UpDownBase; + if (upDownBase != null) + return upDownBase.OnCoerceValue((T)value); + else + return value; + } + + protected virtual T OnCoerceValue(T value) + { + return value; + } + + private static void OnValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) + { + UpDownBase upDownBase = o as UpDownBase; + if (upDownBase != null) + upDownBase.OnValueChanged((T)e.OldValue, (T)e.NewValue); + } + + protected virtual void OnValueChanged(T oldValue, T newValue) + { + SyncTextAndValueProperties(NumericUpDown.ValueProperty, newValue); + + RoutedPropertyChangedEventArgs args = new RoutedPropertyChangedEventArgs(oldValue, newValue); + args.RoutedEvent = NumericUpDown.ValueChangedEvent; + RaiseEvent(args); + } + + #endregion //Value + + #endregion //Properties + + #region Constructors + + internal UpDownBase() { } + + #endregion //Constructors + + #region Base Class Overrides + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + TextBox = GetTemplateChild(ElementTextName) as TextBox; + Spinner = GetTemplateChild(ElementSpinnerName) as Spinner; + Spinner.Spin += OnSpinnerSpin; + } + + protected override void OnPreviewKeyDown(KeyEventArgs e) + { + switch (e.Key) + { + case Key.Up: + { + if (AllowSpin) + DoIncrement(); + e.Handled = true; + break; + } + case Key.Down: + { + if (AllowSpin) + DoDecrement(); + e.Handled = true; + break; + } + //case Key.Enter: + // { + // if (IsEditable) + // SyncTextAndValueProperties(UpDownBase.TextProperty, TextBox.Text); + // break; + // } + } + } + + protected override void OnMouseWheel(MouseWheelEventArgs e) + { + base.OnMouseWheel(e); + + if (!e.Handled && AllowSpin) + { + if (e.Delta < 0) + { + DoDecrement(); + } + else if (0 < e.Delta) + { + DoIncrement(); + } + + e.Handled = true; + } + } + + protected override void OnTextChanged(string oldValue, string newValue) + { + SyncTextAndValueProperties(InputBase.TextProperty, newValue); + } + + #endregion //Base Class Overrides + + #region Event Handlers + + private void OnSpinnerSpin(object sender, SpinEventArgs e) + { + if (AllowSpin) + OnSpin(e); + } + + #endregion //Event Handlers + + #region Events + + public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(NumericUpDown)); + public event RoutedPropertyChangedEventHandler ValueChanged + { + add { AddHandler(ValueChangedEvent, value); } + remove { RemoveHandler(ValueChangedEvent, value); } + } + + #endregion //Events + + #region Methods + + protected virtual void OnSpin(SpinEventArgs e) + { + if (e == null) + throw new ArgumentNullException("e"); + + if (e.Direction == SpinDirection.Increase) + DoIncrement(); + else + DoDecrement(); + } + + /// + /// Performs an increment if conditions allow it. + /// + private void DoDecrement() + { + if (Spinner == null || (Spinner.ValidSpinDirection & ValidSpinDirections.Decrease) == ValidSpinDirections.Decrease) + { + OnDecrement(); + } + } + + /// + /// Performs a decrement if conditions allow it. + /// + private void DoIncrement() + { + if (Spinner == null || (Spinner.ValidSpinDirection & ValidSpinDirections.Increase) == ValidSpinDirections.Increase) + { + OnIncrement(); + } + } + + private void SyncTextAndValueProperties(DependencyProperty p, object newValue) + { + //prevents recursive syncing properties + if (_isSyncingTextAndValueProperties) + return; + + _isSyncingTextAndValueProperties = true; + + //this only occures when the user typed in the value + if (InputBase.TextProperty == p) + { + string text = newValue == null ? String.Empty : newValue.ToString(); + SetValue(UpDownBase.ValueProperty, ConvertTextToValue(text)); + } + + SetValue(InputBase.TextProperty, ConvertValueToText(newValue)); + + _isSyncingTextAndValueProperties = false; + } + + #region Abstract + + /// + /// Called by OnSpin when the spin direction is SpinDirection.Increase. + /// + protected abstract void OnIncrement(); + + /// + /// Called by OnSpin when the spin direction is SpinDirection.Descrease. + /// + protected abstract void OnDecrement(); + + protected abstract T ConvertTextToValue(string text); + + protected abstract string ConvertValueToText(object value); + + #endregion //Abstract + + #endregion //Methods + } }