diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/ButtonSpinner.cs b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/ButtonSpinner.cs index 467f6c85..b2c2ad99 100644 --- a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/ButtonSpinner.cs +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/ButtonSpinner.cs @@ -3,7 +3,6 @@ using System.Windows; using System.Windows.Input; using System.Windows.Markup; using System.Windows.Controls.Primitives; -using Microsoft.Windows.Controls.Primitives; namespace Microsoft.Windows.Controls { diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/SpinDirection.cs b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/SpinDirection.cs similarity index 88% rename from ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/SpinDirection.cs rename to ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/SpinDirection.cs index a5e58cc3..aaa121fb 100644 --- a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/SpinDirection.cs +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/SpinDirection.cs @@ -1,6 +1,6 @@ using System; -namespace Microsoft.Windows.Controls.Primitives +namespace Microsoft.Windows.Controls { /// /// Represents spin directions that could be initiated by the end-user. diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/SpinEventArgs.cs b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/SpinEventArgs.cs similarity index 90% rename from ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/SpinEventArgs.cs rename to ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/SpinEventArgs.cs index 5750f13f..f8a89385 100644 --- a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/SpinEventArgs.cs +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/SpinEventArgs.cs @@ -1,7 +1,7 @@ using System; using System.Windows; -namespace Microsoft.Windows.Controls.Primitives +namespace Microsoft.Windows.Controls { /// /// Provides data for the Spinner.Spin event. diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/Spinner.cs b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/Spinner.cs similarity index 95% rename from ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/Spinner.cs rename to ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/Spinner.cs index cb169de9..20b8d1cb 100644 --- a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/Spinner.cs +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/Spinner.cs @@ -2,7 +2,7 @@ using System.Windows.Controls; using System.Windows; -namespace Microsoft.Windows.Controls.Primitives +namespace Microsoft.Windows.Controls { /// /// Base class for controls that represents controls that can spin. diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/ValidSpinDirections.cs b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/ValidSpinDirections.cs similarity index 86% rename from ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/ValidSpinDirections.cs rename to ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/ValidSpinDirections.cs index 4099bc25..d744620d 100644 --- a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/ValidSpinDirections.cs +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/ButtonSpinner/ValidSpinDirections.cs @@ -1,6 +1,6 @@ using System; -namespace Microsoft.Windows.Controls.Primitives +namespace Microsoft.Windows.Controls { /// /// Represents spin directions that are valid. diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/NumericUpDown/NumericUpDown.cs b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/NumericUpDown/NumericUpDown.cs new file mode 100644 index 00000000..ffd3b7e4 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/NumericUpDown/NumericUpDown.cs @@ -0,0 +1,163 @@ +using System; +using System.Windows; +using System.Globalization; + +namespace Microsoft.Windows.Controls +{ + + public class NumericUpDown : UpDownBase + { + #region Properties + + #region Minimum + + public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(0d, OnMinimumPropertyChanged)); + public double Minimum + { + get { return (double)GetValue(MinimumProperty); } + set { SetValue(MinimumProperty, value); } + } + + private static void OnMinimumPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + } + + protected virtual void OnMinimumChanged(double oldValue, double newValue) + { + } + #endregion Minimum + + #region Maximum + + public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(100d, OnMaximumPropertyChanged)); + public double Maximum + { + get { return (double)GetValue(MaximumProperty); } + set { SetValue(MaximumProperty, value); } + } + + private static void OnMaximumPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + } + + protected virtual void OnMaximumChanged(double oldValue, double newValue) + { + } + #endregion Maximum + + #region Increment + + public static readonly DependencyProperty IncrementProperty = DependencyProperty.Register("Increment", typeof(double), typeof(NumericUpDown), new PropertyMetadata(1d, OnIncrementPropertyChanged)); + public double Increment + { + get { return (double)GetValue(IncrementProperty); } + set { SetValue(IncrementProperty, value); } + } + + private static void OnIncrementPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + } + + protected virtual void OnIncrementChanged(double oldValue, double newValue) + { + } + + #endregion + + #region FormatString + + public static readonly DependencyProperty StringFormatProperty = DependencyProperty.Register("FormatString", typeof(string), typeof(NumericUpDown), new PropertyMetadata("F0", OnStringFormatPropertyPropertyChanged)); + public string FormatString + { + get { return (string)GetValue(StringFormatProperty); } + set { SetValue(StringFormatProperty, value); } + } + + private static void OnStringFormatPropertyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + NumericUpDown nud = d as NumericUpDown; + nud.OnStringFormatChanged(e.OldValue.ToString(), e.NewValue.ToString()); + } + + protected virtual void OnStringFormatChanged(string oldValue, string newValue) + { + Text = FormatValue(); + } + + #endregion //FormatString + + #endregion + + #region Constructors + + public NumericUpDown() + : base() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericUpDown), new FrameworkPropertyMetadata(typeof(NumericUpDown))); + } + + #endregion //Constructors + + #region Base Class Overrides + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + SetValidSpinDirection(); + } + + protected override void OnValueChanged(RoutedPropertyChangedEventArgs e) + { + SetValidSpinDirection(); + } + + protected override double ParseValue(string text) + { + return double.Parse(text, NumberStyles.Any, CultureInfo.CurrentCulture); + } + + protected internal override string FormatValue() + { + return Value.ToString(FormatString, CultureInfo.CurrentCulture); + } + + protected override void OnIncrement() + { + Value = (double)((decimal)Value + (decimal)Increment); + } + + protected override void OnDecrement() + { + Value = (double)((decimal)Value - (decimal)Increment); + } + + #endregion //Base Class Overrides + + #region Methods + + /// + /// Sets the valid spin direction based on current value, minimum and maximum. + /// + private void SetValidSpinDirection() + { + ValidSpinDirections validDirections = ValidSpinDirections.None; + + if (Value < Maximum) + { + validDirections = validDirections | ValidSpinDirections.Increase; + } + + if (Value > Minimum) + { + validDirections = validDirections | ValidSpinDirections.Decrease; + } + + if (Spinner != null) + { + Spinner.ValidSpinDirection = validDirections; + } + } + + #endregion //Methods + } +} diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Themes/Generic.xaml b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Themes/Generic.xaml index 5c8adc47..cc768c0a 100644 --- a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Themes/Generic.xaml +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Themes/Generic.xaml @@ -930,16 +930,18 @@ + + - + - + - + @@ -947,9 +949,9 @@ - + - + @@ -957,51 +959,51 @@ - + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/UpDownBase/UpDownBase.cs b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/UpDownBase/UpDownBase.cs new file mode 100644 index 00000000..19a05583 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/UpDownBase/UpDownBase.cs @@ -0,0 +1,331 @@ +using System; +using System.Windows.Input; +using System.Windows.Controls; +using System.Windows; + +namespace Microsoft.Windows.Controls +{ + public abstract class UpDownBase : Control + { + #region Members + + /// + /// Name constant for Text template part. + /// + internal const string ElementTextName = "Text"; + + /// + /// 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 + /// + bool _isSyncingTextAndValueProperties; + + #endregion //Members + + #region Properties + + #region Value + + public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(T), typeof(UpDownBase), new FrameworkPropertyMetadata(default(T), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnValuePropertyChanged)); + public virtual T Value + { + get { return (T)GetValue(ValueProperty); } + set { SetValue(ValueProperty, value); } + } + + private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + UpDownBase udb = (UpDownBase)d; + T oldValue = (T)e.OldValue; + T newValue = (T)e.NewValue; + + udb.SyncTextAndValueProperties(e.Property, e.NewValue); + + RoutedPropertyChangedEventArgs changedArgs = new RoutedPropertyChangedEventArgs(oldValue, newValue); + udb.OnValueChanged(changedArgs); + } + + protected virtual void OnValueChanged(RoutedPropertyChangedEventArgs e) + { + if (ValueChanged != null) + ValueChanged(this, e); + } + + #endregion //Value + + #region Text + + public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(UpDownBase), new FrameworkPropertyMetadata("0", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnTextPropertyChanged)); + public string Text + { + get { return (string)GetValue(TextProperty); } + set { SetValue(TextProperty, value); } + } + + private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + NumericUpDown nud = (NumericUpDown)d; + nud.SyncTextAndValueProperties(e.Property, e.NewValue); + } + + protected virtual void OnTextChanged(string oldValue, string newValue) + { + + } + + #endregion //Text + + #region IsEditable + + public static readonly DependencyProperty IsEditableProperty = DependencyProperty.Register("IsEditable", typeof(bool), typeof(UpDownBase), new PropertyMetadata(true, OnIsEditablePropertyChanged)); + public bool IsEditable + { + get { return (bool)GetValue(IsEditableProperty); } + set { SetValue(IsEditableProperty, value); } + } + + private static void OnIsEditablePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + UpDownBase source = d as UpDownBase; + source.OnIsEditableChanged((bool)e.OldValue, (bool)e.NewValue); + } + + protected virtual void OnIsEditableChanged(bool oldValue, bool newValue) + { + if (TextBox != null) + TextBox.IsReadOnly = !IsEditable; + } + + #endregion //IsEditable + + internal TextBox TextBox { get; private set; } + + private Spinner _spinner; + internal Spinner Spinner + { + get { return _spinner; } + private set + { + if (_spinner != null) + { + _spinner.Spin -= OnSpinnerSpin; + } + + _spinner = value; + + if (_spinner != null) + { + _spinner.Spin += OnSpinnerSpin; + } + } + } + + #endregion //Properties + + #region Constructors + + protected UpDownBase() + { + } + + #endregion //Constructors + + #region Base Class Overrides + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + TextBox = GetTemplateChild(ElementTextName) as TextBox; + Spinner = GetTemplateChild(ElementSpinnerName) as Spinner; + + if (TextBox != null) + TextBox.IsReadOnly = !IsEditable; + } + + protected override void OnPreviewKeyDown(KeyEventArgs e) + { + switch (e.Key) + { + case Key.Up: + { + DoIncrement(); + e.Handled = true; + break; + } + case Key.Down: + { + DoDecrement(); + e.Handled = true; + break; + } + } + } + + protected override void OnMouseWheel(MouseWheelEventArgs e) + { + base.OnMouseWheel(e); + + if (!e.Handled) + { + if (e.Delta < 0) + { + DoDecrement(); + } + else if (0 < e.Delta) + { + DoIncrement(); + } + + e.Handled = true; + } + } + + #endregion //Base Class Overrides + + #region Methods + + #region Abstract + + /// + /// Called by ApplyValue to parse user input. + /// + /// User input. + /// Value parsed from user input. + protected abstract T ParseValue(string text); + + /// + /// Renders the value property into the textbox text. + /// + /// Formatted Value. + protected internal abstract string FormatValue(); + + /// + /// 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(); + + #endregion //Abstract + + #region Protected + + /// + /// GetValue override to return Value property as object type. + /// + /// The Value property as object type. + protected object GetValue() + { + return Value; + } + + /// + /// SetValue override to set value to Value property. + /// + /// New value. + protected void SetValue(object value) + { + Value = (T)value; + } + + #endregion //Protected + + #region Private + + /// + /// 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; + + if (NumericUpDown.ValueProperty == p) + { + SetValue(NumericUpDown.TextProperty, FormatValue()); + } + else if (NumericUpDown.TextProperty == p) + { + SetValue(NumericUpDown.ValueProperty, ParseValue(newValue.ToString())); + } + + _isSyncingTextAndValueProperties = false; + } + + #endregion //Private + + #region Virtual + + /// + /// Occurs when the spinner spins. + /// + /// Event args. + protected virtual void OnSpin(SpinEventArgs e) + { + if (e == null) + throw new ArgumentNullException("e"); + + if (e.Direction == SpinDirection.Increase) + DoIncrement(); + else + DoDecrement(); + } + + #endregion //Virtual + + #endregion //Methods + + #region Event Handlers + + /// + /// Event handler for Spinner template part's Spin event. + /// + /// The Spinner template part. + /// Event args. + private void OnSpinnerSpin(object sender, SpinEventArgs e) + { + OnSpin(e); + } + + #endregion //Event Handlers + + #region Events + + /// + /// Occurs when Value property has changed. + /// + public event RoutedPropertyChangedEventHandler ValueChanged; + + #endregion //Events + } +} diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/WPFToolkit.Extended.csproj b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/WPFToolkit.Extended.csproj index 627f466e..fe315047 100644 --- a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/WPFToolkit.Extended.csproj +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/WPFToolkit.Extended.csproj @@ -72,11 +72,12 @@ - - - - + + + + + Code @@ -102,6 +103,7 @@ + @@ -142,6 +144,7 @@ +