Browse Source

Major overhaul of NumericUpDown, DateTimeUpDown, and MaskedTextBox in order to support null values. Need extensive testing because I am sure I broke something.

pull/1645/head
brianlagunas_cp 16 years ago
parent
commit
faa7825423
  1. 146
      ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/InputBase.cs
  2. 12
      ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/UpDownBase.cs
  3. 134
      ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/DateTimeUpDown/Implementation/DateTimeUpDown.cs
  4. 189
      ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/MaskedTextBox/Implementation/MaskedTextBox.cs
  5. 285
      ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/NumericUpDown/Implementation/NumericUpDown.cs
  6. 4
      ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/PropertyGrid/Implementation/PropertyGrid.cs
  7. 1
      ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/WPFToolkit.Extended.csproj

146
ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/InputBase.cs

@ -6,20 +6,8 @@ namespace Microsoft.Windows.Controls.Primitives
{ {
public abstract class InputBase : Control public abstract class InputBase : Control
{ {
#region Members
/// <summary>
/// Flags if the Text and Value properties are in the process of being sync'd
/// </summary>
private bool _isSyncingTextAndValueProperties;
private bool _isInitialized;
#endregion //Members
#region Properties #region Properties
public virtual object PreviousValue { get; internal set; }
#region IsEditable #region IsEditable
public static readonly DependencyProperty IsEditableProperty = DependencyProperty.Register("IsEditable", typeof(bool), typeof(InputBase), new PropertyMetadata(true)); public static readonly DependencyProperty IsEditableProperty = DependencyProperty.Register("IsEditable", typeof(bool), typeof(InputBase), new PropertyMetadata(true));
@ -33,19 +21,17 @@ namespace Microsoft.Windows.Controls.Primitives
#region Text #region Text
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(InputBase), new FrameworkPropertyMetadata(default(String), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnTextPropertyChanged)); public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(InputBase), new PropertyMetadata(default(String), OnTextPropertyChanged));
public string Text public string Text
{ {
get { return (string)this.GetValue(TextProperty); } get { return (string)GetValue(TextProperty); }
set { this.SetValue(TextProperty, value); } set { SetValue(TextProperty, value); }
} }
private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{ {
InputBase input = (InputBase)d; InputBase input = (InputBase)d;
input.OnTextChanged((string)e.OldValue, (string)e.NewValue); input.OnTextChanged((string)e.OldValue, (string)e.NewValue);
if (input._isInitialized)
input.SyncTextAndValueProperties(e.Property, e.NewValue);
} }
protected virtual void OnTextChanged(string previousValue, string currentValue) protected virtual void OnTextChanged(string previousValue, string currentValue)
@ -55,132 +41,6 @@ namespace Microsoft.Windows.Controls.Primitives
#endregion //Text #endregion //Text
#region Value
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(InputBase), new FrameworkPropertyMetadata(default(object), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnValuePropertyChanged, OnCoerceValuePropertyCallback));
public virtual object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
InputBase input = (InputBase)d;
if (e.OldValue != e.NewValue)
{
input.PreviousValue = e.OldValue;
input.OnValueChanged(e.OldValue, e.NewValue);
if (input._isInitialized)
input.SyncTextAndValueProperties(e.Property, e.NewValue);
}
}
protected virtual void OnValueChanged(object oldValue, object newValue)
{
RoutedPropertyChangedEventArgs<object> args = new RoutedPropertyChangedEventArgs<object>(oldValue, newValue);
args.RoutedEvent = InputBase.ValueChangedEvent;
RaiseEvent(args);
}
private static object OnCoerceValuePropertyCallback(DependencyObject d, object baseValue)
{
InputBase inputBase = d as InputBase;
if (inputBase != null)
return inputBase.OnCoerceValue(baseValue);
else
return baseValue;
}
protected virtual object OnCoerceValue(object value)
{
return value;
}
#endregion //Value
#region ValueType
public static readonly DependencyProperty ValueTypeProperty = DependencyProperty.Register("ValueType", typeof(Type), typeof(InputBase), new FrameworkPropertyMetadata(typeof(String), FrameworkPropertyMetadataOptions.None, new PropertyChangedCallback(OnValueTypePropertyChanged)));
public Type ValueType
{
get { return (Type)GetValue(ValueTypeProperty); }
set { SetValue(ValueTypeProperty, value); }
}
private static void OnValueTypePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
InputBase input = (InputBase)d;
input.OnValueTypeChanged((Type)e.OldValue, (Type)e.NewValue);
}
protected virtual void OnValueTypeChanged(Type oldValue, Type newType)
{
if (_isInitialized)
SyncTextAndValueProperties(TextProperty, Text);
}
#endregion //ValueType
#endregion //Properties #endregion //Properties
#region Base Class Overrides
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
if (!_isInitialized)
{
_isInitialized = true;
SyncTextAndValueProperties(ValueProperty, Value);
}
}
#endregion //Base Class Overrides
#region Events
public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<object>), typeof(InputBase));
public event RoutedPropertyChangedEventHandler<object> ValueChanged
{
add { AddHandler(ValueChangedEvent, value); }
remove { RemoveHandler(ValueChangedEvent, value); }
}
#endregion //Events
#region Methods
protected 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)
{
SetValue(InputBase.ValueProperty, ConvertTextToValue(newValue.ToString()));
}
SetValue(InputBase.TextProperty, ConvertValueToText(newValue));
_isSyncingTextAndValueProperties = false;
}
#endregion //Methods
#region Abstract
protected abstract object ConvertTextToValue(string text);
protected abstract string ConvertValueToText(object value);
#endregion //Abstract
} }
} }

12
ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Core/Primitives/UpDownBase.cs

@ -95,12 +95,12 @@ namespace Microsoft.Windows.Controls.Primitives
e.Handled = true; e.Handled = true;
break; break;
} }
case Key.Enter: //case Key.Enter:
{ // {
if (IsEditable) // if (IsEditable)
SyncTextAndValueProperties(UpDownBase.TextProperty, TextBox.Text); // SyncTextAndValueProperties(UpDownBase.TextProperty, TextBox.Text);
break; // break;
} // }
} }
} }

134
ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/DateTimeUpDown/Implementation/DateTimeUpDown.cs

@ -14,6 +14,7 @@ namespace Microsoft.Windows.Controls
private List<DateTimeInfo> _dateTimeInfoList = new List<DateTimeInfo>(); private List<DateTimeInfo> _dateTimeInfoList = new List<DateTimeInfo>();
private DateTimeInfo _selectedDateTimeInfo; private DateTimeInfo _selectedDateTimeInfo;
private bool _fireSelectionChangedEvent = true; private bool _fireSelectionChangedEvent = true;
private bool _isSyncingTextAndValueProperties;
#endregion //Members #endregion //Members
@ -21,6 +22,8 @@ namespace Microsoft.Windows.Controls
private DateTimeFormatInfo DateTimeFormatInfo { get; set; } private DateTimeFormatInfo DateTimeFormatInfo { get; set; }
//TODO: add minimum and maximum properties
#region Format #region Format
public static readonly DependencyProperty FormatProperty = DependencyProperty.Register("Format", typeof(DateTimeFormat), typeof(DateTimeUpDown), new UIPropertyMetadata(DateTimeFormat.FullDateTime, OnFormatChanged)); public static readonly DependencyProperty FormatProperty = DependencyProperty.Register("Format", typeof(DateTimeFormat), typeof(DateTimeUpDown), new UIPropertyMetadata(DateTimeFormat.FullDateTime, OnFormatChanged));
@ -72,6 +75,58 @@ namespace Microsoft.Windows.Controls
#endregion //FormatString #endregion //FormatString
#region Value
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(DateTime?), typeof(DateTimeUpDown), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnValueChanged, OnCoerceValue));
public DateTime? Value
{
get { return (DateTime?)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
private static object OnCoerceValue(DependencyObject o, object value)
{
DateTimeUpDown dateTimeUpDown = o as DateTimeUpDown;
if (dateTimeUpDown != null)
return dateTimeUpDown.OnCoerceValue((DateTime?)value);
else
return value;
}
protected virtual DateTime? OnCoerceValue(DateTime? value)
{
//if the user entered a string value to represent a date or time, we need to parse that string into a valid DatTime value
if (value != null && !(value is DateTime))
{
return DateTime.Parse(value.ToString(), DateTimeFormatInfo);
}
return value;
}
private static void OnValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
DateTimeUpDown dateTimeUpDown = o as DateTimeUpDown;
if (dateTimeUpDown != null)
dateTimeUpDown.OnValueChanged((DateTime?)e.OldValue, (DateTime?)e.NewValue);
}
protected virtual void OnValueChanged(DateTime? oldValue, DateTime? newValue)
{
//whenever the value changes we need to parse out the value into out DateTimeInfo segments so we can keep track of the individual pieces
//but only if it is not null
if (newValue != null)
ParseValueIntoDateTimeInfo();
SyncTextAndValueProperties(DateTimeUpDown.ValueProperty, newValue);
RoutedPropertyChangedEventArgs<DateTime?> args = new RoutedPropertyChangedEventArgs<DateTime?>(oldValue, newValue);
args.RoutedEvent = DateTimeUpDown.ValueChangedEvent;
RaiseEvent(args);
}
#endregion //Value
#endregion //Properties #endregion //Properties
#region Constructors #region Constructors
@ -79,7 +134,6 @@ namespace Microsoft.Windows.Controls
static DateTimeUpDown() static DateTimeUpDown()
{ {
DefaultStyleKeyProperty.OverrideMetadata(typeof(DateTimeUpDown), new FrameworkPropertyMetadata(typeof(DateTimeUpDown))); DefaultStyleKeyProperty.OverrideMetadata(typeof(DateTimeUpDown), new FrameworkPropertyMetadata(typeof(DateTimeUpDown)));
ValueTypeProperty.OverrideMetadata(typeof(DateTimeUpDown), new FrameworkPropertyMetadata(typeof(Nullable<DateTime>)));
} }
public DateTimeUpDown() public DateTimeUpDown()
@ -130,27 +184,6 @@ namespace Microsoft.Windows.Controls
base.OnPreviewKeyDown(e); base.OnPreviewKeyDown(e);
} }
protected override void OnValueChanged(object oldValue, object newValue)
{
//whenever the value changes we need to parse out the value into out DateTimeInfo segments so we can keep track of the individual pieces
//but only if it is not null
if (newValue != null)
ParseValueIntoDateTimeInfo();
base.OnValueChanged(oldValue, newValue);
}
protected override object OnCoerceValue(object value)
{
//if the user entered a string value to represent a date or time, we need to parse that string into a valid DatTime value
if (value != null && !(value is DateTime))
{
return DateTime.Parse(value.ToString(), DateTimeFormatInfo);
}
return base.OnCoerceValue(value);
}
#endregion //Base Class Overrides #endregion //Base Class Overrides
#region Event Hanlders #region Event Hanlders
@ -165,6 +198,17 @@ namespace Microsoft.Windows.Controls
#endregion //Event Hanlders #endregion //Event Hanlders
#region Events
public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<DateTime?>), typeof(DateTimeUpDown));
public event RoutedPropertyChangedEventHandler<DateTime?> ValueChanged
{
add { AddHandler(ValueChangedEvent, value); }
remove { RemoveHandler(ValueChangedEvent, value); }
}
#endregion //Events
#region Methods #region Methods
#region Abstract #region Abstract
@ -181,19 +225,6 @@ namespace Microsoft.Windows.Controls
UpdateDateTime(-1); UpdateDateTime(-1);
} }
protected override object ConvertTextToValue(string text)
{
throw new NotImplementedException("ConvertTextToValue");
}
protected override string ConvertValueToText(object value)
{
if (value == null) return string.Empty;
DateTime dt = DateTime.Parse(value.ToString(), CultureInfo.CurrentCulture);
return dt.ToString(GetFormatString(Format), CultureInfo.CurrentCulture);
}
#endregion //Abstract #endregion //Abstract
#region Private #region Private
@ -539,6 +570,39 @@ namespace Microsoft.Windows.Controls
#endregion //Private #endregion //Private
protected object ConvertTextToValue(string text)
{
throw new NotImplementedException("ConvertTextToValue");
}
protected string ConvertValueToText(object value)
{
if (value == null) return string.Empty;
DateTime dt = DateTime.Parse(value.ToString(), CultureInfo.CurrentCulture);
return dt.ToString(GetFormatString(Format), CultureInfo.CurrentCulture);
}
protected 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(DateTimeUpDown.ValueProperty, ConvertTextToValue(text));
}
SetValue(InputBase.TextProperty, ConvertValueToText(newValue));
_isSyncingTextAndValueProperties = false;
}
#endregion //Methods #endregion //Methods
} }
} }

189
ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/MaskedTextBox/Implementation/MaskedTextBox.cs

@ -9,6 +9,16 @@ namespace Microsoft.Windows.Controls
{ {
public class MaskedTextBox : InputBase public class MaskedTextBox : InputBase
{ {
#region Members
/// <summary>
/// Flags if the Text and Value properties are in the process of being sync'd
/// </summary>
private bool _isSyncingTextAndValueProperties;
private bool _isInitialized;
#endregion //Members
#region Properties #region Properties
protected MaskedTextProvider MaskProvider { get; set; } protected MaskedTextProvider MaskProvider { get; set; }
@ -84,6 +94,58 @@ namespace Microsoft.Windows.Controls
#endregion //Mask #endregion //Mask
#region Value
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(MaskedTextBox), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnValueChanged));
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
private static void OnValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
MaskedTextBox maskedTextBox = o as MaskedTextBox;
if (maskedTextBox != null)
maskedTextBox.OnValueChanged((object)e.OldValue, (object)e.NewValue);
}
protected virtual void OnValueChanged(object oldValue, object newValue)
{
if (_isInitialized)
SyncTextAndValueProperties(DateTimeUpDown.ValueProperty, newValue);
RoutedPropertyChangedEventArgs<object> args = new RoutedPropertyChangedEventArgs<object>(oldValue, newValue);
args.RoutedEvent = MaskedTextBox.ValueChangedEvent;
RaiseEvent(args);
}
#endregion //Value
#region ValueType
public static readonly DependencyProperty ValueTypeProperty = DependencyProperty.Register("ValueType", typeof(Type), typeof(MaskedTextBox), new UIPropertyMetadata(typeof(String), OnValueTypeChanged));
public Type ValueType
{
get { return (Type)GetValue(ValueTypeProperty); }
set { SetValue(ValueTypeProperty, value); }
}
private static void OnValueTypeChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
MaskedTextBox maskedTextBox = o as MaskedTextBox;
if (maskedTextBox != null)
maskedTextBox.OnValueTypeChanged((Type)e.OldValue, (Type)e.NewValue);
}
protected virtual void OnValueTypeChanged(Type oldValue, Type newValue)
{
if (_isInitialized)
SyncTextAndValueProperties(InputBase.TextProperty, Text);
}
#endregion //ValueType
#endregion //Properties #endregion //Properties
#region Constructors #region Constructors
@ -115,48 +177,27 @@ namespace Microsoft.Windows.Controls
base.OnAccessKey(e); base.OnAccessKey(e);
} }
protected override object ConvertTextToValue(string text) protected override void OnGotFocus(RoutedEventArgs e)
{ {
object convertedValue = null; if (TextBox != null)
TextBox.Focus();
Type dataType = ValueType; }
string valueToConvert = MaskProvider.ToString(); protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
if (valueToConvert.GetType() == dataType || dataType.IsInstanceOfType(valueToConvert)) if (!_isInitialized)
{
convertedValue = valueToConvert;
}
#if !VS2008
else if (String.IsNullOrWhiteSpace(valueToConvert))
{
convertedValue = Activator.CreateInstance(dataType);
}
#else
else if (String.IsNullOrEmpty(valueToConvert))
{ {
convertedValue = Activator.CreateInstance(dataType); _isInitialized = true;
SyncTextAndValueProperties(ValueProperty, Value);
} }
#endif
else if (null == convertedValue && valueToConvert is IConvertible)
{
convertedValue = Convert.ChangeType(valueToConvert, dataType);
}
return convertedValue;
} }
protected override string ConvertValueToText(object value) protected override void OnTextChanged(string previousValue, string currentValue)
{ {
if (value == null) if (_isInitialized)
value = string.Empty; SyncTextAndValueProperties(InputBase.TextProperty, currentValue);
//I have only seen this occur while in Blend, but we need it here so the Blend designer doesn't crash.
if (MaskProvider == null)
return value.ToString();
MaskProvider.Set(value.ToString());
return MaskProvider.ToDisplayString();
} }
#endregion #endregion
@ -247,6 +288,17 @@ namespace Microsoft.Windows.Controls
#endregion //Event Handlers #endregion //Event Handlers
#region Events
public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<object>), typeof(MaskedTextBox));
public event RoutedPropertyChangedEventHandler<object> ValueChanged
{
add { AddHandler(ValueChangedEvent, value); }
remove { RemoveHandler(ValueChangedEvent, value); }
}
#endregion //Events
#region Methods #region Methods
#region Private #region Private
@ -284,20 +336,69 @@ namespace Microsoft.Windows.Controls
#endregion //Private #endregion //Private
#region Public private object ConvertTextToValue(string text)
{
object convertedValue = null;
/// <summary> Type dataType = ValueType;
/// Attempts to set focus to this element.
/// </summary> string valueToConvert = MaskProvider.ToString().Trim();
public new void Focus()
if (valueToConvert.GetType() == dataType || dataType.IsInstanceOfType(valueToConvert))
{
convertedValue = valueToConvert;
}
#if !VS2008
else if (String.IsNullOrWhiteSpace(valueToConvert))
{
convertedValue = Activator.CreateInstance(dataType);
}
#else
else if (String.IsNullOrEmpty(valueToConvert))
{
convertedValue = Activator.CreateInstance(dataType);
}
#endif
else if (null == convertedValue && valueToConvert is IConvertible)
{
convertedValue = Convert.ChangeType(valueToConvert, dataType);
}
return convertedValue;
}
private string ConvertValueToText(object value)
{ {
if (TextBox != null) if (value == null)
TextBox.Focus(); value = string.Empty;
else
base.Focus(); //I have only seen this occur while in Blend, but we need it here so the Blend designer doesn't crash.
if (MaskProvider == null)
return value.ToString();
MaskProvider.Set(value.ToString());
return MaskProvider.ToDisplayString();
} }
#endregion //Public protected 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)
{
if (newValue != null)
SetValue(MaskedTextBox.ValueProperty, ConvertTextToValue(newValue.ToString()));
}
SetValue(InputBase.TextProperty, ConvertValueToText(newValue));
_isSyncingTextAndValueProperties = false;
}
#endregion //Methods #endregion //Methods

285
ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/NumericUpDown/Implementation/NumericUpDown.cs

@ -8,6 +8,15 @@ namespace Microsoft.Windows.Controls
{ {
public class NumericUpDown : UpDownBase public class NumericUpDown : UpDownBase
{ {
#region Members
/// <summary>
/// Flags if the Text and Value properties are in the process of being sync'd
/// </summary>
private bool _isSyncingTextAndValueProperties;
#endregion //Members
#region Properties #region Properties
#region Minimum #region Minimum
@ -88,6 +97,64 @@ namespace Microsoft.Windows.Controls
#endregion //SelectAllOnGotFocus #endregion //SelectAllOnGotFocus
#region Value
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(decimal?), typeof(NumericUpDown), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnValueChanged, OnCoerceValue));
public decimal? Value
{
get { return (decimal?)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
private static object OnCoerceValue(DependencyObject o, object value)
{
NumericUpDown numericUpDown = o as NumericUpDown;
if (numericUpDown != null)
return numericUpDown.OnCoerceValue((decimal?)value);
else
return value;
}
protected virtual decimal? OnCoerceValue(decimal? value)
{
if (value == null) return value;
decimal val = value.Value;
if (val < Minimum)
{
return Minimum;
}
else if (val > Maximum)
{
return Maximum;
}
else
{
return value;
}
}
private static void OnValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
NumericUpDown numericUpDown = o as NumericUpDown;
if (numericUpDown != null)
numericUpDown.OnValueChanged((decimal?)e.OldValue, (decimal?)e.NewValue);
}
protected virtual void OnValueChanged(decimal? oldValue, decimal? newValue)
{
SetValidSpinDirection();
SyncTextAndValueProperties(NumericUpDown.ValueProperty, newValue);
RoutedPropertyChangedEventArgs<decimal?> args = new RoutedPropertyChangedEventArgs<decimal?>(oldValue, newValue);
args.RoutedEvent = NumericUpDown.ValueChangedEvent;
RaiseEvent(args);
}
#endregion //Value
#endregion #endregion
#region Constructors #region Constructors
@ -95,14 +162,20 @@ namespace Microsoft.Windows.Controls
static NumericUpDown() static NumericUpDown()
{ {
DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericUpDown), new FrameworkPropertyMetadata(typeof(NumericUpDown))); DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericUpDown), new FrameworkPropertyMetadata(typeof(NumericUpDown)));
ValueTypeProperty.OverrideMetadata(typeof(NumericUpDown), new FrameworkPropertyMetadata(typeof(decimal)));
ValueProperty.OverrideMetadata(typeof(NumericUpDown), new FrameworkPropertyMetadata(default(decimal)));
} }
#endregion //Constructors #endregion //Constructors
#region Base Class Overrides #region Base Class Overrides
protected override void OnAccessKey(AccessKeyEventArgs e)
{
if (TextBox != null)
TextBox.Focus();
base.OnAccessKey(e);
}
public override void OnApplyTemplate() public override void OnApplyTemplate()
{ {
base.OnApplyTemplate(); base.OnApplyTemplate();
@ -116,93 +189,38 @@ namespace Microsoft.Windows.Controls
} }
} }
protected override void OnAccessKey(AccessKeyEventArgs e)
{
if (TextBox != null)
TextBox.Focus();
base.OnAccessKey(e);
}
protected override void OnGotFocus(RoutedEventArgs e) protected override void OnGotFocus(RoutedEventArgs e)
{ {
if (TextBox != null) if (TextBox != null)
TextBox.Focus(); TextBox.Focus();
} }
protected override void OnValueChanged(object oldValue, object newValue) protected override void OnIncrement()
{ {
SetValidSpinDirection(); if (Value.HasValue)
base.OnValueChanged(oldValue, newValue); Value += Increment;
} }
protected override object OnCoerceValue(object value) protected override void OnDecrement()
{ {
if (value == null) return value; if (Value.HasValue)
Value -= Increment;
decimal val = Convert.ToDecimal(value);
if (val < Minimum)
{
return Minimum;
}
else if (val > Maximum)
{
return Maximum;
}
else
{
return value;
}
} }
protected override object ConvertTextToValue(string text) protected override void OnPreviewKeyDown(KeyEventArgs e)
{ {
object result = null; base.OnPreviewKeyDown(e);
NumberFormatInfo info = NumberFormatInfo.GetInstance(CultureInfo.CurrentCulture);
try
{
result = FormatString.Contains("P") ? ParsePercent(text, ValueType, info) : ParseDataValue(text, ValueType, info);
}
catch
{
TextBox.Text = Text = ConvertValueToText(Value);
return Value;
}
return result; if (e.Key == Key.Enter)
}
protected override string ConvertValueToText(object value)
{
//TODO: create GetTextFromValue methods for each data type;
if (value is double)
{ {
double d = (double)value; if (IsEditable)
SyncTextAndValueProperties(InputBase.TextProperty, TextBox.Text);
if (Double.IsNaN(d))
return "NaN";
else if (Double.IsPositiveInfinity(d) || Double.MaxValue == d)
return "Infinity";
else if (Double.IsNegativeInfinity(d) || Double.MinValue == d)
return "Negative-Infinity";
} }
return (Convert.ToDecimal(Value)).ToString(FormatString, CultureInfo.CurrentCulture);
}
protected override void OnIncrement()
{
decimal newValue = (Convert.ToDecimal(Value) + Increment);
Value = ValueType != typeof(Decimal) ? Convert.ChangeType(newValue, ValueType) : newValue;
} }
protected override void OnDecrement() protected override void OnTextChanged(string previousValue, string currentValue)
{ {
decimal newValue = (Convert.ToDecimal(Value) - Increment); SyncTextAndValueProperties(InputBase.TextProperty, currentValue);
Value = ValueType != typeof(Decimal) ? Convert.ChangeType(newValue, ValueType) : newValue;
} }
#endregion //Base Class Overrides #endregion //Base Class Overrides
@ -225,75 +243,67 @@ namespace Microsoft.Windows.Controls
#endregion //Event Handlers #endregion //Event Handlers
#region Methods #region Events
/// <summary> public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<decimal?>), typeof(NumericUpDown));
/// Sets the valid spin direction based on current value, minimum and maximum. public event RoutedPropertyChangedEventHandler<decimal?> ValueChanged
/// </summary>
private void SetValidSpinDirection()
{ {
ValidSpinDirections validDirections = ValidSpinDirections.None; add { AddHandler(ValueChangedEvent, value); }
remove { RemoveHandler(ValueChangedEvent, value); }
}
if (Convert.ToDecimal(Value) < Maximum) #endregion //Events
{
validDirections = validDirections | ValidSpinDirections.Increase;
}
if (Convert.ToDecimal(Value) > Minimum) #region Methods
{
validDirections = validDirections | ValidSpinDirections.Decrease;
}
if (Spinner != null) private decimal? ConvertTextToValue(string text)
{ {
Spinner.ValidSpinDirection = validDirections; decimal? result = null;
}
}
#region Parsing if (String.IsNullOrEmpty(text))
return result;
NumberFormatInfo info = NumberFormatInfo.GetInstance(CultureInfo.CurrentCulture);
private static object ParseDataValue(string text, Type dataType, NumberFormatInfo info)
{
try try
{ {
if (typeof(decimal) == dataType) result = FormatString.Contains("P") ? ParsePercent(text, info) : ParseDecimal(text, info);
{
return ParseDecimal(text, info);
}
else if (typeof(double) == dataType)
{
return ParseDouble(text, info);
}
else if (typeof(float) == dataType)
{
return ParseFloat(text, info);
}
else if (typeof(byte) == dataType || typeof(sbyte) == dataType ||
typeof(short) == dataType || typeof(ushort) == dataType || typeof(Int16) == dataType ||
typeof(int) == dataType || typeof(uint) == dataType || typeof(Int32) == dataType ||
typeof(long) == dataType || typeof(ulong) == dataType || typeof(Int64) == dataType)
{
return ParseWholeNumber(text, dataType, info);
}
else
{
throw new ArgumentException("Type not supported");
}
} }
catch (Exception ex) catch
{ {
throw; Text = ConvertValueToText(Value);
return Value;
} }
return result;
} }
private static double ParseDouble(string text, NumberFormatInfo info) private string ConvertValueToText(object value)
{ {
return double.Parse(text, NumberStyles.Any, info); if (!Value.HasValue)
return String.Empty;
return Value.Value.ToString(FormatString, CultureInfo.CurrentCulture);
} }
private static float ParseFloat(string text, NumberFormatInfo info) private void SyncTextAndValueProperties(DependencyProperty p, object newValue)
{ {
return float.Parse(text, NumberStyles.Any, info); //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(NumericUpDown.ValueProperty, ConvertTextToValue(text));
}
SetValue(InputBase.TextProperty, ConvertValueToText(newValue));
_isSyncingTextAndValueProperties = false;
} }
private static decimal ParseDecimal(string text, NumberFormatInfo info) private static decimal ParseDecimal(string text, NumberFormatInfo info)
@ -301,23 +311,38 @@ namespace Microsoft.Windows.Controls
return decimal.Parse(text, NumberStyles.Any, info); return decimal.Parse(text, NumberStyles.Any, info);
} }
private static object ParseWholeNumber(string text, Type dataType, NumberFormatInfo info) private static decimal ParsePercent(string text, NumberFormatInfo info)
{
decimal result = decimal.Parse(text, NumberStyles.Any, info);
return Convert.ChangeType(result, dataType, info);
}
private static object ParsePercent(string text, Type dataType, NumberFormatInfo info)
{ {
text = text.Replace(info.PercentSymbol, null); text = text.Replace(info.PercentSymbol, null);
decimal result = decimal.Parse(text, NumberStyles.Any, info); decimal result = decimal.Parse(text, NumberStyles.Any, info);
result = result / 100; result = result / 100;
return Convert.ChangeType(result, dataType, info); return result;
} }
#endregion /// <summary>
/// Sets the valid spin direction based on current value, minimum and maximum.
/// </summary>
private void SetValidSpinDirection()
{
ValidSpinDirections validDirections = ValidSpinDirections.None;
if (Convert.ToDecimal(Value) < Maximum)
{
validDirections = validDirections | ValidSpinDirections.Increase;
}
if (Convert.ToDecimal(Value) > Minimum)
{
validDirections = validDirections | ValidSpinDirections.Decrease;
}
if (Spinner != null)
{
Spinner.ValidSpinDirection = validDirections;
}
}
#endregion //Methods #endregion //Methods
} }

4
ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/PropertyGrid/Implementation/PropertyGrid.cs

@ -322,9 +322,7 @@ namespace Microsoft.Windows.Controls.PropertyGrid
editor = new TextBlockEditor(); editor = new TextBlockEditor();
else if (propertyItem.PropertyType == typeof(bool)) else if (propertyItem.PropertyType == typeof(bool))
editor = new CheckBoxEditor(); editor = new CheckBoxEditor();
else if (propertyItem.PropertyType == typeof(int)) else if (propertyItem.PropertyType == typeof(double) || propertyItem.PropertyType == typeof(int))
editor = new IntegerUpDownEditor();
else if (propertyItem.PropertyType == typeof(double))
editor = new NumericUpDownEditor(); editor = new NumericUpDownEditor();
else if (propertyItem.PropertyType == typeof(DateTime)) else if (propertyItem.PropertyType == typeof(DateTime))
editor = new DateTimeUpDownEditor(); editor = new DateTimeUpDownEditor();

1
ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/WPFToolkit.Extended.csproj

@ -210,7 +210,6 @@
<Compile Include="PropertyGrid\Implementation\Editors\EnumComboBoxEditor.cs" /> <Compile Include="PropertyGrid\Implementation\Editors\EnumComboBoxEditor.cs" />
<Compile Include="PropertyGrid\Implementation\Editors\FontComboBoxEditor.cs" /> <Compile Include="PropertyGrid\Implementation\Editors\FontComboBoxEditor.cs" />
<Compile Include="PropertyGrid\Implementation\Editors\ICustomTypeEditor.cs" /> <Compile Include="PropertyGrid\Implementation\Editors\ICustomTypeEditor.cs" />
<Compile Include="PropertyGrid\Implementation\Editors\IntegerUpDownEditor.cs" />
<Compile Include="PropertyGrid\Implementation\Editors\ITypeEditor.cs" /> <Compile Include="PropertyGrid\Implementation\Editors\ITypeEditor.cs" />
<Compile Include="PropertyGrid\Implementation\Editors\NumericUpDownEditor.cs" /> <Compile Include="PropertyGrid\Implementation\Editors\NumericUpDownEditor.cs" />
<Compile Include="PropertyGrid\Implementation\Editors\TextBlockEditor.cs" /> <Compile Include="PropertyGrid\Implementation\Editors\TextBlockEditor.cs" />

Loading…
Cancel
Save