Description: When binding to a null value, the RadSpinEditor throws an exception. This missing functionality is also noticed with the standard Windows Numeric Up Down control. How to reproduce: - add a RadSpinEditor and two RadButtons; - use the following code: public partial class Form1 : Form { private BindingSource _bindActiveObject = new BindingSource { DataSource = typeof(MyBindingObject) }; public Form1() { InitializeComponent(); this.radSpinEditor1.DataBindings.Add(new Binding("Value", _bindActiveObject, "MyValue")); } private void radButton1_Click(object sender, EventArgs e) { _bindActiveObject.DataSource = new MyBindingObject { MyValue = Convert.ToDouble(100) }; } private void radButton2_Click(object sender, EventArgs e) { _bindActiveObject.DataSource = new MyBindingObject { MyValue = null }; } } public class MyBindingObject { private decimal? _myValue; public decimal? MyValue { get { return _myValue; } set { _myValue = value; } } } Workaround: Use the following custom RadSpinEditor: private BindingSource _bindActiveObject = new BindingSource { DataSource = typeof(MyBindingObject) }; public Form1() { InitializeComponent(); this.radSpinEditor1.NullableValueChanged += Form1_NullableValueChanged; this.radSpinEditor1.DecimalPlaces = 2; this.radSpinEditor1.DataBindings.Add(new Binding("NullableValue", _bindActiveObject, "MyValue", true, DataSourceUpdateMode.OnPropertyChanged)); } private void Form1_NullableValueChanged(object sender, EventArgs e) { Console.WriteLine("NullableValue = " + this.radSpinEditor1.NullableValue + ""); } private void radButton1_Click(object sender, EventArgs e) { MyBindingObject obj = new MyBindingObject { MyValue = 65.45m }; _bindActiveObject.DataSource = obj; } private void radButton2_Click(object sender, EventArgs e) { _bindActiveObject.DataSource = new MyBindingObject { MyValue = null }; } public class MyBindingObject { private decimal? _myValue; public decimal? MyValue { get { return _myValue; } set { _myValue = value; } } } public class MySpinEditor : RadSpinEditor { public event EventHandler NullableValueChanged; public decimal? NullableValue { get { return (this.SpinElement as MySpinEditorElement).NullableValue; } set { (this.SpinElement as MySpinEditorElement).NullableValue = value; } } public MySpinEditor() { this.AutoSize = true; this.TabStop = false; base.SetStyle(ControlStyles.Selectable, true); } protected override void CreateChildItems(RadElement parent) { Type baseType = typeof(RadSpinEditor); MySpinEditorElement element = new MySpinEditorElement(); element.RightToLeft = this.RightToLeft == System.Windows.Forms.RightToLeft.Yes; this.RootElement.Children.Add(element); element.ValueChanging += spinElement_ValueChanging; element.ValueChanged += spinElement_ValueChanged; element.TextChanging += spinElement_TextChanging; element.NullableValueChanged += element_NullableValueChanged; element.KeyDown += OnSpinElementKeyDown; element.KeyPress += OnSpinElementKeyPress; element.KeyUp += OnSpinElementKeyUp; baseType.GetField("spinElement", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(this, element); } void element_NullableValueChanged(object sender, EventArgs e) { if (this.NullableValueChanged != null) { this.NullableValueChanged(this, EventArgs.Empty); } } private Dictionary<string, MethodInfo> cache = new Dictionary<string, MethodInfo>(); private void InvokeBaseMethod(string name, params object[] parameters) { if (!cache.ContainsKey(name)) { cache[name] = typeof(RadSpinEditor).GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic); } cache[name].Invoke(this, parameters); } private void OnSpinElementKeyUp(object sender, KeyEventArgs e) { this.InvokeBaseMethod("OnSpinElementKeyUp", sender, e); } private void OnSpinElementKeyPress(object sender, KeyPressEventArgs e) { this.InvokeBaseMethod("OnSpinElementKeyPress", sender, e); } private void OnSpinElementKeyDown(object sender, KeyEventArgs e) { this.InvokeBaseMethod("OnSpinElementKeyDown", sender, e); } private void spinElement_TextChanging(object sender, TextChangingEventArgs e) { this.InvokeBaseMethod("spinElement_TextChanging", sender, e); } private void spinElement_ValueChanged(object sender, EventArgs e) { this.InvokeBaseMethod("spinElement_ValueChanged", sender, e); this.NullableValue = this.Value; } private void spinElement_ValueChanging(object sender, ValueChangingEventArgs e) { this.InvokeBaseMethod("spinElement_ValueChanging", sender, e); } protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { if (keyData == Keys.Tab) { (this.SpinElement as MySpinEditorElement).CommitText(); } else if (keyData== Keys.Delete) { (this.SpinElement as MySpinEditorElement).NullableValue = null; } return base.ProcessCmdKey(ref msg, keyData); } protected override Size DefaultSize { get { return GetDpiScaledSize(new Size(100, 20)); } } } public class MySpinEditorElement : RadSpinElement { private bool validating; private decimal? nullableValue; private RadButtonElement nullButton; public decimal? NullableValue { get { return this.nullableValue; } set { this.nullableValue = value; if (value.HasValue) { this.internalValue = value.Value; } else { this.internalValue = 0m; } this.Validate(); this.OnNullableValueChanged(); } } protected override void OnKeyDown(KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { this.CommitText(); e.Handled = true; return; } base.OnKeyDown(e); } void nullButton_Click(object sender, EventArgs e) { this.NullableValue = null; } public virtual void CommitText() { this.NullableValue = this.GetValueFromText(); } protected override decimal GetValueFromText() { if (this.TextBoxItem.Text == "") { return 0m; } return base.GetValueFromText(); } public override bool Validate() { if (!this.NullableValue.HasValue) { this.TextBoxItem.Text = ""; return true; } this.TextBoxItem.Text = this.GetTextFromNumber(this.NullableValue.HasValue ? this.internalValue : 0m, this.Hexadecimal, this.ThousandsSeparator, this.DecimalPlaces); return true; } private string GetTextFromNumber(decimal num, bool hex, bool thousands, int decimalPlaces) { if (hex) { return string.Format("{0:X}", (long)num); } return num.ToString((thousands ? "N" : "F") + decimalPlaces.ToString(CultureInfo.CurrentCulture), CultureInfo.CurrentCulture); } public override void PerformStep(decimal step) { decimal value = this.GetValueFromText(); try { decimal incValue = value + step; value = incValue; } catch (OverflowException) { } this.NullableValue = this.Constrain(value); this.Validate(); } protected override Type ThemeEffectiveType { get { return typeof(RadSpinElement); } } public event EventHandler NullableValueChanged; protected virtual void OnNullableValueChanged() { if (this.NullableValueChanged != null) { this.NullableValueChanged(this, EventArgs.Empty); } } }