Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NumericUpDown: Fixes #952 and improve stability #953

Merged
merged 9 commits into from
Jan 21, 2014
129 changes: 84 additions & 45 deletions MahApps.Metro/Controls/NumericUpDown.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,49 @@ public class NumericUpDown : Control
public static readonly DependencyProperty DelayProperty = DependencyProperty.Register("Delay",
typeof(int),
typeof(NumericUpDown),
new FrameworkPropertyMetadata(DefaultDelay, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnDelayChanged),
new FrameworkPropertyMetadata(DefaultDelay, OnDelayChanged),
ValidateDelay);

public static readonly DependencyProperty TextAlignmentProperty = TextBox.TextAlignmentProperty.AddOwner(typeof(NumericUpDown));

public static readonly DependencyProperty SpeedupProperty = DependencyProperty.Register("Speedup",
typeof(bool),
typeof(NumericUpDown),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSpeedupChanged));

public static readonly DependencyProperty IsReadOnlyProperty = TextBoxBase.IsReadOnlyProperty.AddOwner(typeof(NumericUpDown), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));
public static readonly DependencyProperty StringFormatProperty = DependencyProperty.Register("StringFormat", typeof(string), typeof(NumericUpDown), new FrameworkPropertyMetadata(null, OnStringFormatChanged));
public static readonly DependencyProperty InterceptArrowKeysProperty = DependencyProperty.Register("InterceptArrowKeys", typeof(bool), typeof(NumericUpDown), new FrameworkPropertyMetadata(true));
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double?), typeof(NumericUpDown), new FrameworkPropertyMetadata(default(double?), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnValueChanged, CoerceValue));
public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(NumericUpDown), new FrameworkPropertyMetadata(double.MinValue, OnMinimumChanged));
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(NumericUpDown), new FrameworkPropertyMetadata(double.MaxValue, OnMaximumChanged, CoerceMaximum));
public static readonly DependencyProperty IntervalProperty = DependencyProperty.Register("Interval", typeof(double), typeof(NumericUpDown), new PropertyMetadata((double)1, IntervalChanged));
new FrameworkPropertyMetadata(true, OnSpeedupChanged));

public static readonly DependencyProperty IsReadOnlyProperty = TextBoxBase.IsReadOnlyProperty.AddOwner(typeof(NumericUpDown),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));

public static readonly DependencyProperty StringFormatProperty = DependencyProperty.Register("StringFormat",
typeof(string),
typeof(NumericUpDown),
new FrameworkPropertyMetadata(string.Empty, OnStringFormatChanged, CoerceStringFormat));

public static readonly DependencyProperty InterceptArrowKeysProperty = DependencyProperty.Register("InterceptArrowKeys",
typeof(bool),
typeof(NumericUpDown),
new FrameworkPropertyMetadata(true));

public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value",
typeof(double?),
typeof(NumericUpDown),
new FrameworkPropertyMetadata(default(double?), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnValueChanged, CoerceValue));

public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum",
typeof(double),
typeof(NumericUpDown),
new FrameworkPropertyMetadata(double.MinValue, OnMinimumChanged));

public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum",
typeof(double),
typeof(NumericUpDown),
new FrameworkPropertyMetadata(double.MaxValue, OnMaximumChanged, CoerceMaximum));

public static readonly DependencyProperty IntervalProperty = DependencyProperty.Register("Interval",
typeof(double),
typeof(NumericUpDown),
new FrameworkPropertyMetadata(DefaultInterval, IntervalChanged));

private const double DefaultInterval = 1d;
private const int DefaultDelay = 500;
private const string ElementNumericDown = "PART_NumericDown";
Expand All @@ -59,7 +85,7 @@ public class NumericUpDown : Control
#endregion

private double _internalIntervalMultiplierForCalculation = DefaultInterval;
private double _internalLargeChange;
private double _internalLargeChange = DefaultInterval * 100;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this is better add in the constructor of the instances no ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can, but since DefaultInterval is a const there would be no differences.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah ok, if is a const ok :P

private double _intervalValueSinceReset;
private bool _manualChange;
private RepeatButton _repeatDown;
Expand Down Expand Up @@ -237,7 +263,9 @@ public override void OnApplyTemplate()

_valueTextBox = GetTemplateChild(ElementTextBox) as TextBox;

if (_repeatUp == null || _repeatDown == null || _valueTextBox == null)
if (_repeatUp == null ||
_repeatDown == null ||
_valueTextBox == null)
{
throw new InvalidOperationException(string.Format("You have missed to specify {0}, {1} or {2} in your template", ElementNumericUp, ElementNumericDown, ElementTextBox));
}
Expand Down Expand Up @@ -313,7 +341,8 @@ protected void OnPreviewTextInput(object sender, TextCompositionEventArgs e)
const StringComparison strComp = StringComparison.InvariantCultureIgnoreCase;

e.Handled = true;
if (string.IsNullOrWhiteSpace(e.Text) || e.Text.Length != 1)
if (string.IsNullOrWhiteSpace(e.Text) ||
e.Text.Length != 1)
{
return;
}
Expand All @@ -339,15 +368,16 @@ protected void OnPreviewTextInput(object sender, TextCompositionEventArgs e)
}
else
{
if (numberFormatInfo.NegativeSign == text || text == numberFormatInfo.PositiveSign)
if (numberFormatInfo.NegativeSign == text ||
text == numberFormatInfo.PositiveSign)
{
if (textBox.SelectionStart == 0)
{
//check if text already has a + or - sign
if (textBox.Text.Length > 1)
{
if (!textBox.Text.StartsWith(numberFormatInfo.NegativeSign, strComp)
&& !textBox.Text.StartsWith(numberFormatInfo.PositiveSign, strComp))
if (!textBox.Text.StartsWith(numberFormatInfo.NegativeSign, strComp) &&
!textBox.Text.StartsWith(numberFormatInfo.PositiveSign, strComp))
{
e.Handled = false;
}
Expand All @@ -366,9 +396,9 @@ protected void OnPreviewTextInput(object sender, TextCompositionEventArgs e)
}
}
}
else if (text.Equals(scientificNotationChar, strComp)
&& !textBox.Text.Any(i => i.ToString(equivalentCulture).Equals(scientificNotationChar, strComp))
&& StringFormat.ToUpperInvariant().Contains(scientificNotationChar))
else if (text.Equals(scientificNotationChar, strComp) &&
textBox.SelectionStart > 0 &&
!textBox.Text.Any(i => i.ToString(equivalentCulture).Equals(scientificNotationChar, strComp)))
{
e.Handled = false;
}
Expand All @@ -378,28 +408,6 @@ protected void OnPreviewTextInput(object sender, TextCompositionEventArgs e)

protected virtual void OnSpeedupChanged(bool oldSpeedup, bool newSpeedup) {}

private void EnableDisableUpDown()
{
EnableDisableUp();
EnableDisableDown();
}

private void EnableDisableUp()
{
if (_repeatUp != null)
{
_repeatUp.IsEnabled = Value < Maximum;
}
}

private void EnableDisableDown()
{
if (_repeatDown != null)
{
_repeatDown.IsEnabled = Value > Minimum;
}
}

/// <summary>
/// Raises the <see cref="E:System.Windows.Controls.Primitives.RangeBase.ValueChanged" /> routed event.
/// </summary>
Expand All @@ -411,18 +419,21 @@ private void EnableDisableDown()
/// </param>
protected virtual void OnValueChanged(double? oldValue, double? newValue)
{
if (!newValue.HasValue && _valueTextBox != null)
if (!newValue.HasValue &&
_valueTextBox != null)
{
_valueTextBox.Text = null;
return;
}

if (_repeatUp != null && !_repeatUp.IsEnabled)
if (_repeatUp != null &&
!_repeatUp.IsEnabled)
{
_repeatUp.IsEnabled = true;
}

if (_repeatDown != null && !_repeatDown.IsEnabled)
if (_repeatDown != null &&
!_repeatDown.IsEnabled)
{
_repeatDown.IsEnabled = true;
}
Expand Down Expand Up @@ -485,6 +496,11 @@ private static object CoerceMaximum(DependencyObject d, object value)
return val < minimum ? minimum : val;
}

private static object CoerceStringFormat(DependencyObject d, object basevalue)
{
return basevalue ?? string.Empty;
}

private static object CoerceValue(DependencyObject d, object value)
{
if (value == null)
Expand Down Expand Up @@ -551,7 +567,8 @@ private static void OnStringFormatChanged(DependencyObject d, DependencyProperty
{
NumericUpDown nud = (NumericUpDown)d;

if (nud._valueTextBox != null && nud.Value.HasValue)
if (nud._valueTextBox != null &&
nud.Value.HasValue)
{
nud._valueTextBox.Text = nud.Value.Value.ToString((string)e.NewValue);
}
Expand Down Expand Up @@ -599,6 +616,28 @@ private void ChangeValue(bool toPositive)
}
}

private void EnableDisableDown()
{
if (_repeatDown != null)
{
_repeatDown.IsEnabled = Value > Minimum;
}
}

private void EnableDisableUp()
{
if (_repeatUp != null)
{
_repeatUp.IsEnabled = Value < Maximum;
}
}

private void EnableDisableUpDown()
{
EnableDisableUp();
EnableDisableDown();
}

private void OnGetFocus(object sender, RoutedEventArgs e)
{
_valueTextBox.Focus();
Expand Down