简体   繁体   中英

DataGridView: Object of type 'System.DBNull' cannot be converted to type 'System.Decimal'

I have a c# DataGridView that is bound to a c# BindingList. A user-modifiable text column is bound to a decimal value. When the decimal value of the bound object contains 0, an empty cell is correctly displayed as empty rather than showing 0 (ie, CellFormatting handler displays "" instead of 0). If the user enters 0, then that gets passed on to the bound object and an empty cell is displayed, so that all works fine.

I would like the behavior to be the same if the user clears the cell; however, I get an exception:

System.ArgumentException: Object of type 'System.DBNull' cannot be converted to type 'System.Decimal'.
   at System.ComponentModel.ReflectPropertyDescriptor.SetValue(Object component, Object value)
   at System.Windows.Forms.DataGridView.DataGridViewDataConnection.PushValue(Int32 boundColumnIndex, Int32 columnIndex, Int32 rowIndex, Object value)

In the CellValidating event I do:

string priceString = e.FormattedValue.ToString();
if (String.IsNullOrWhiteSpace(priceString))
{
  boundObject.decimalValue = 0;
}

So that works in the sense that the bound object does get its decimal value correctly set to 0, but I'd like to avoid that exception.

e.FormattedValue is read-only so I can't modify that; I also tried using

dataGridView[e.ColumnIndex, e.RowIndex].Value = 0m;

but that doesn't solve the problem.

Can I do anything in CellValidating to avoid this issue? Or do I need to modify the value somehwere else (CellEndEdit? CellValueChanged? Somewhere else?)

Thanks!

The new value needs to be handled in the OnCellParsing(...) method. Eg:

public class Form5 : Form {
    
    public Form5() {
        List<Person> list = new List<Person>();
        list.Add(new Person { Name = "A", Age = 1 });
        list.Add(new Person {Name = "B", Age = 2 });
        list.Add(new Person {Name = "Z", Age = 0 });

        DGV dgv = new DGV { Dock = DockStyle.Fill };
        var bindingList = new BindingList<Person>(list);
        dgv.DataSource = bindingList;
        dgv.BindingContext = new BindingContext();

        Controls.Add(dgv);
    }

    public class DGV : DataGridView {
        ErrorProvider errorProvider = new ErrorProvider { BlinkStyle = ErrorBlinkStyle.NeverBlink };
        public DGV() {
            AllowUserToAddRows = false;
        }

        protected override void OnCellFormatting(DataGridViewCellFormattingEventArgs e) {
            base.OnCellFormatting(e);
            if (e.Value is decimal && ((decimal) e.Value) == 0m)
                e.Value = "";
        }

        protected override void OnCellParsing(DataGridViewCellParsingEventArgs e) {
            base.OnCellParsing(e);
            String s = e.Value.ToString();
            if (String.IsNullOrWhiteSpace(s)) {
                e.Value = 0m;
                e.ParsingApplied = true; // important, otherwise the value reverts back to the original value
            }
            else {
                decimal val = 0m;
                if (decimal.TryParse(s, out val))
                    e.Value = val;
            }
        }

        protected override void OnDataError(bool displayErrorDialogIfNoHandler, DataGridViewDataErrorEventArgs e) {
            base.OnDataError(false, e);
            Control c = this.EditingControl;
            errorProvider.SetError(c, e.Exception.Message);
            errorProvider.SetIconAlignment(c, ErrorIconAlignment.MiddleLeft);
            errorProvider.SetIconPadding(c, -20);
        }

        protected override void OnCellEndEdit(DataGridViewCellEventArgs e) {
            base.OnCellEndEdit(e);
            errorProvider.Clear();
        }
    }

    public class Person {
        public String Name { get; set; }
        public decimal Age { get; set; }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM