1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2005 Novell, Inc.
23 // Jonathan Gilbert <logic@deltaq.org>
25 // Integration into MWF:
26 // Peter Bartok <pbartok@novell.com>
30 using System.Collections;
31 using System.ComponentModel;
33 using System.Globalization;
34 using System.Runtime.InteropServices;
36 using System.Windows.Forms;
38 namespace System.Windows.Forms {
39 [DefaultEvent("ValueChanged")]
40 [DefaultProperty("Value")]
41 [DefaultBindingProperty ("Value")]
42 [ClassInterface (ClassInterfaceType.AutoDispatch)]
44 public class NumericUpDown : UpDownBase, ISupportInitialize {
45 #region Local Variables
46 private bool suppress_validation;
47 private int decimal_places;
48 private bool hexadecimal;
49 private decimal increment;
50 private decimal maximum;
51 private decimal minimum;
52 private bool thousands_separator;
53 private decimal dvalue;
56 NumericUpDownAccelerationCollection accelerations;
57 // private long buttonPressedTicks;
58 //private bool isSpinning;
59 #endregion // Local Variables
61 #region UIA FrameWork Events
62 static object UIAMinimumChangedEvent = new object ();
64 internal event EventHandler UIAMinimumChanged {
65 add { Events.AddHandler (UIAMinimumChangedEvent, value); }
66 remove { Events.RemoveHandler (UIAMinimumChangedEvent, value); }
69 internal void OnUIAMinimumChanged (EventArgs e)
71 EventHandler eh = (EventHandler) Events [UIAMinimumChangedEvent];
76 static object UIAMaximumChangedEvent = new object ();
78 internal event EventHandler UIAMaximumChanged {
79 add { Events.AddHandler (UIAMaximumChangedEvent, value); }
80 remove { Events.RemoveHandler (UIAMaximumChangedEvent, value); }
83 internal void OnUIAMaximumChanged (EventArgs e)
85 EventHandler eh = (EventHandler) Events [UIAMaximumChangedEvent];
90 static object UIASmallChangeChangedEvent = new object ();
92 internal event EventHandler UIASmallChangeChanged {
93 add { Events.AddHandler (UIASmallChangeChangedEvent, value); }
94 remove { Events.RemoveHandler (UIASmallChangeChangedEvent, value); }
97 internal void OnUIASmallChangeChanged (EventArgs e)
99 EventHandler eh = (EventHandler) Events [UIASmallChangeChangedEvent];
105 #region Public Constructors
106 public NumericUpDown() {
107 suppress_validation = false;
113 thousands_separator = false;
117 #endregion // Public Constructors
119 #region Public Instance Properties
122 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
123 public NumericUpDownAccelerationCollection Accelerations {
125 if (accelerations == null)
126 accelerations = new NumericUpDownAccelerationCollection ();
127 return accelerations;
132 public int DecimalPlaces {
134 return decimal_places;
138 decimal_places = value;
143 [DefaultValue(false)]
144 public bool Hexadecimal {
155 public decimal Increment {
163 throw new ArgumentOutOfRangeException("value", value, "NumericUpDown increment cannot be negative");
168 // UIA Framework Event: SmallChange Changed
169 OnUIASmallChangeChanged (EventArgs.Empty);
173 [RefreshProperties(RefreshProperties.All)]
174 public decimal Maximum {
182 if (minimum > maximum)
185 if (dvalue > maximum)
188 // UIA Framework Event: Maximum Changed
189 OnUIAMaximumChanged (EventArgs.Empty);
193 [RefreshProperties(RefreshProperties.All)]
194 public decimal Minimum {
202 if (maximum < minimum)
205 if (dvalue < minimum)
208 // UIA Framework Event: Minimum Changed
209 OnUIAMinimumChanged (EventArgs.Empty);
214 [EditorBrowsable (EditorBrowsableState.Never)]
215 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
216 public new Padding Padding {
217 get { return Padding.Empty; }
223 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
224 [EditorBrowsable(EditorBrowsableState.Never)]
225 public override string Text {
235 [DefaultValue(false)]
237 public bool ThousandsSeparator {
239 return thousands_separator;
243 thousands_separator = value;
249 public decimal Value {
257 if (value != dvalue) {
258 if (!suppress_validation && ((value < minimum) || (value > maximum))) {
259 throw new ArgumentOutOfRangeException ("value", "NumericUpDown.Value must be within the specified Minimum and Maximum values");
263 OnValueChanged (EventArgs.Empty);
268 #endregion // Public Instance Properties
270 #region Public Instance Methods
271 public void BeginInit() {
272 suppress_validation = true;
275 public void EndInit() {
276 suppress_validation = false;
277 Value = Check (dvalue);
281 public override string ToString() {
282 return string.Format("{0}, Minimum = {1}, Maximum = {2}", base.ToString(), minimum, maximum);
285 public override void DownButton() {
290 Value = Math.Max (minimum, unchecked (dvalue - increment));
292 // UIA Framework Event: DownButton Click
293 OnUIADownButtonClick (EventArgs.Empty);
296 public override void UpButton() {
301 Value = Math.Min (maximum, unchecked (dvalue + increment));
303 // UIA Framework Event: UpButton Click
304 OnUIAUpButtonClick (EventArgs.Empty);
306 #endregion // Public Instance Methods
308 #region Protected Instance Methods
309 protected override AccessibleObject CreateAccessibilityInstance() {
310 AccessibleObject acc;
312 acc = new AccessibleObject(this);
313 acc.role = AccessibleRole.SpinButton;
318 protected override void OnTextBoxKeyPress(object source, KeyPressEventArgs e) {
319 if ((ModifierKeys & ~Keys.Shift) != Keys.None) {
323 NumberFormatInfo nfi = CultureInfo.CurrentCulture.NumberFormat;
324 string pressedKey = e.KeyChar.ToString ();
326 if ((pressedKey != nfi.NegativeSign) && (pressedKey != nfi.NumberDecimalSeparator) &&
327 (pressedKey != nfi.NumberGroupSeparator)) {
328 string acceptable = hexadecimal ? "\b0123456789abcdefABCDEF" : "\b0123456789";
329 if (acceptable.IndexOf (e.KeyChar) == -1) {
330 // FIXME: produce beep to signal that "invalid" key was pressed
331 // prevent the key from reaching the text box
336 base.OnTextBoxKeyPress(source, e);
339 protected virtual void OnValueChanged(EventArgs e) {
340 EventHandler eh = (EventHandler)(Events [ValueChangedEvent]);
345 protected void ParseEditText () {
348 Value = Check (decimal.Parse (Text, CultureInfo.CurrentCulture));
350 Value = Check (Convert.ToDecimal (Convert.ToInt32 (Text, 16)));
359 private decimal Check (decimal val)
373 protected override void UpdateEditText () {
374 if (suppress_validation)
382 // "N" and "F" differ only in that "N" includes commas
383 // every 3 digits to the left of the decimal and "F"
386 string format_string;
388 if (thousands_separator) {
394 format_string += decimal_places;
396 Text = dvalue.ToString (format_string, CultureInfo.CurrentCulture);
399 // Cast to Int64 to be able to use the "X" formatter.
400 // If the value is below Int64.MinValue or above Int64.MaxValue,
401 // then an OverflowException will be thrown, as with .NET.
402 Text = ((Int64)dvalue).ToString("X", CultureInfo.CurrentCulture);
407 protected override void ValidateEditText() {
412 protected override void OnLostFocus(EventArgs e) {
418 protected override void OnKeyUp (KeyEventArgs e)
420 // isSpinning = false;
424 protected override void OnKeyDown (KeyEventArgs e)
426 // buttonPressedTicks = DateTime.Now.Ticks;
427 // isSpinning = true;
430 #endregion // Protected Instance Methods
434 [EditorBrowsable (EditorBrowsableState.Never)]
435 public new event EventHandler PaddingChanged {
436 add { base.PaddingChanged += value; }
437 remove { base.PaddingChanged -= value; }
440 static object ValueChangedEvent = new object ();
442 public event EventHandler ValueChanged {
443 add { Events.AddHandler (ValueChangedEvent, value); }
444 remove { Events.RemoveHandler (ValueChangedEvent, value); }
448 [EditorBrowsable(EditorBrowsableState.Never)]
449 public new event EventHandler TextChanged {
450 add { base.TextChanged += value; }
451 remove { base.TextChanged -= value; }