Object of type 'System.DBNull' cannot be converted to type 'System.String'. When throwing an exception from property.

1 Answer 77 Views
GridView
Jong
Top achievements
Rank 1
Veteran
Jong asked on 13 May 2021, 04:58 PM

Hello, 

I have two issues.

The first issue is that I'm binding a Model to RadGridView, and throwing an exception when a value is invalid, and when throwing an exception from a property and catching it with DataError, GridViewDataErrorEventArgs.Exception is not the exception that was thrown from the property, but I get Object of type 'System.DBNull' cannot be converted to type 'System.String'.

This only happens when the property is null or empty string.

FYI, I'm allowing incorrect values to be assigned and do the validation after assigning the value to the property, and this is what I want, because I want to give the user an opportunity to correct base on the original value they entered.

Another issue is that when drawing borders to indicate which cell has a problem, not all borders appear.

As you can see above, I'm missing the top border.

It happens to another theme and sometimes the right side border is missing.

How can I make it so that all the borders appear?

The below is the sample code that you can use to reproduce the errors.

To reproduce the first problem, edit the first cell, clear the value, and the property will throw a "Please enter category name." exception but the exception in RadGridView1_DataError is Object of type 'System.DBNull' cannot be converted to type 'System.String' not the exception thrwon from the property setter.

To reproduce the second problem, edit the first cell, enter any value that is longer than 5 characters and you will see the red border without the top border.


public partial class GridViewTestForm : Form
{
    public GridViewTestForm()
    {
        InitializeComponent();

        List<GridViewDataColumn> gridColumns = new List<GridViewDataColumn>();

        gridColumns.Add(new GridViewTextBoxColumn
        {
            DataType = typeof(string),
            TextAlignment = ContentAlignment.MiddleLeft,
            FieldName = nameof(ReportCategoryViewModel.CategoryName),
            HeaderText = "Category Name",
            AutoSizeMode = BestFitColumnMode.DisplayedCells,
        });

        gridColumns.Add(new GridViewTextBoxColumn
        {
            DataType = typeof(string),
            TextAlignment = ContentAlignment.MiddleLeft,
            FieldName = nameof(ReportCategoryViewModel.NumberOfReportsUsingCategory),
            HeaderText = "# Reports",
            ReadOnly = true,
            AutoSizeMode = BestFitColumnMode.DisplayedCells,
        });

        gridColumns.Add(new GridViewTextBoxColumn
        {
            DataType = typeof(string),
            TextAlignment = ContentAlignment.MiddleLeft,
            FieldName = nameof(ReportCategoryViewModel.Description),
            HeaderText = "Description",
        });

        // Add the columns to the grid
        radGridView1.MasterTemplate.Columns.AddRange(gridColumns);
        radGridView1.EnableSorting = true;
        radGridView1.MasterTemplate.AllowMultiColumnSorting = true;

        radGridView1.DataError += RadGridView1_DataError;
        radGridView1.CellValidating += RadGridView1_CellValidating;

        var viewModel = new ReportCategoryManagementViewModel();
        viewModel.LoadReportCategories();
        radGridView1.DataSource = viewModel.ReportCategories;
    }

    private void RadGridView1_CellValidating(object sender, CellValidatingEventArgs e)
    {
        radGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = string.Empty;
        radGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Style.CustomizeBorder = false;
    }

    private void RadGridView1_DataError(object sender, GridViewDataErrorEventArgs e)
    {
        radGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = e.Exception.Message;
        radGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Style.CustomizeBorder = true;
        radGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Style.DrawBorder = true;
        radGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Style.BorderWidth = 1;
        radGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Style.BorderGradientStyle = Telerik.WinControls.GradientStyles.Solid;
        radGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Style.BorderColor = Color.Red;
        e.Cancel = true;
    }
}
public class NotifyPropertyBase : INotifyPropertyChanged
{
    public bool IgnoreValidation { get; set; } = false;
    public event PropertyChangedEventHandler PropertyChanged;
    public virtual void OnPropertyChangedRaised([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
public class ReportCategoryManagementViewModel : NotifyPropertyBase
{
    private ObservableCollection<ReportCategoryViewModel> _reportCategories = null;
    public ObservableCollection<ReportCategoryViewModel> ReportCategories => _reportCategories;
    public event EventHandler<List<ReportCategoryViewModel>> ReportCategoriesLoaded;
    public bool _isBusy = false;
    public bool IsBusy { get => _isBusy; set { if (_isBusy != value) { _isBusy = value; OnPropertyChangedRaised(); } } }
    public ReportCategoryManagementViewModel()
    {

    }
    public void LoadReportCategories()
    {
        _reportCategories = new ObservableCollection<ReportCategoryViewModel>()
        {
            new ReportCategoryViewModel()
            {
                IgnoreValidation = true,
                CategoryName = "My category",
                NumberOfReportsUsingCategory = 2,
                Description = "my optional description for my category"
            }
        };
        foreach(var category in _reportCategories)
            category.IgnoreValidation = false;
    }
}
public class ReportCategoryViewModel : NotifyPropertyBase
{
    public EntityState State { get; private set; } = EntityState.Unchanged;
    private string _categoryName = string.Empty;
    public string CategoryName
    {
        get => _categoryName;
        set
        {
            if (_categoryName != value)
            {
                _categoryName = value;
                OnPropertyChangedRaised();
                if (!IgnoreValidation)
                {
                    if (!string.IsNullOrWhiteSpace(_categoryName))
                    {
                        if (_categoryName.Length > 5)
                            throw new Exception("Maximum character is 5.");
                    }
                    else
                    {
                        _categoryName = string.Empty;
                        throw new Exception("Please enter category name.");
                    }
                }
            }
        }
    }
    private int _numberOfReportsUsingCategory;
    public int NumberOfReportsUsingCategory { get => _numberOfReportsUsingCategory; set { if (_numberOfReportsUsingCategory != value) { _numberOfReportsUsingCategory = value; OnPropertyChangedRaised(); } } }
    private string _description;
    public string Description { get => _description; set { if (_description != value) { _description = value; OnPropertyChangedRaised(); } } }
}

 

1 Answer, 1 is accepted

Sort by
0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 17 May 2021, 10:59 AM

Hello, Jong,

The provided sample code snippet is greatly appreciated. I was able to build a sample project and test the behavior locally. 

Please make sure that there is no negative row/cell spacing to deal with the missing top border:

            this.radGridView1.TableElement.CellSpacing = 0;
            this.radGridView1.TableElement.RowSpacing = 0;

As to the DataError event, it is expected to be different because actually setting null to the category internally is not possible and the "try" block doesn't succeed. For the maximum of 5 characters, the value still will be possible to be set to the respective property considering the type.

A better option for data validation is to check the value before actually setting it to the underlying DataSource. Please have a look at the following help article and consider using the CellValidating event: 

https://docs.telerik.com/devtools/winforms/controls/gridview/editors/data-validation

I hope this information helps. If you need any further assistance please don't hesitate to contact me. 

Regards,
Dess | Tech Support Engineer, Sr.
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Tags
GridView
Asked by
Jong
Top achievements
Rank 1
Veteran
Answers by
Dess | Tech Support Engineer, Principal
Telerik team
Share this question
or