当DGV绑定到DataTable时,如何防止空白字符串变为DBNull.Value

时间:2019-03-20 21:08:32

标签: c# winforms datagridview

很难发布代码,但易于描述如何复制:

创建一个新的Winforms项目(我使用VS 2017和.NET 4.7)

  1. 将数据集添加到项目中。
  2. 在数据集中,添加一个数据表(无适配器)。
  3. 在DataTable中,添加一列。它将默认为varchar,但将其更改为不允许空值。
  4. 向项目添加表单。
  5. 将DataGridView添加到表单。
  6. 将DGV的数据源设置为数据集中的数据表。
  7. 运行程序。
  8. 单击单行的单列。
  9. 输入一些内容。
  10. 选择所有内容并按退格键。
  11. 单击出现的第二行。

会发生什么:引发System.Data.NoNullAllowedException,指示数据列不允许DBNull.Value。

会发生什么:绑定到dgv第一行的行中的列应设置为空白,而不是null。

我尝试过的事情:

  • 使用CellEndEdit处理程序捕获错误值并将其转换为string.Empty。实际上,这确实可以修复某些情况(当一列以上时)
  • 使用CellValidating处理程序-没有帮助
  • 使用CellFormatting处理程序-没有帮助
  • 使用CellParsing处理程序-没有帮助
  • 在BindingSource上使用AddingNew处理程序来提供具有非空值的新行-无济于事

还有其他想法吗?

3 个答案:

答案 0 :(得分:2)

可以将DataGridView配置为适应所需的使用情况,以便在收到空输入时发送Empty.String

发件人:DataGridViewCellStyle.DataSourceNullValue Property

  

获取或设置用户在单元格中输入空值时保存到数据源的值。

发件人:DataGridViewColumn.DefaultCellStyle Property

  

获取或设置列的默认单元格样式。

以上属性用于配置DataGridView。但是,DataTable需要稍作修改。

发件人:DataColumn.DefaultValue Property

  

在创建新行时获取或设置列的默认值。

您可能会认为DataGridVierwColumn的CellTemplate的DefaultNewRowValue Property会提供此功能,但在绑定列的情况下不会提供此功能。如果使用了其他列,并且此属性未更改为默认值,则原始问题将重新出现。

下面的示例旨在按照复制指南中的说明处理您的问题,并假定DataGridview.DataSource设置为DataTableDataView实例。设置DataSource属性后,它将使用DataGridView.BindingContextChanged事件来处理DataGridView的自动生成的列。

public partial class Form1 : Form
{
    private DataTable dt;
    public Form1()
    {
        InitializeComponent();
        dataGridView1.BindingContextChanged += new System.EventHandler(this.dataGridView1_BindingContextChanged);
        dt = new DataTable();
        DataColumn dc = dt.Columns.Add("C0");
        dc.AllowDBNull = false;
        dataGridView1.DataSource = dt.DefaultView;
    }

    private void dataGridView1_BindingContextChanged(object sender, EventArgs e)
    {
        if (dataGridView1.DataSource != null)
        {
            DataTable boundTable = dataGridView1.DataSource as DataTable;
            if (boundTable == null)
            {
                DataView dv = dataGridView1.DataSource as DataView;
                if (dv != null)
                {
                    boundTable = dv.Table;
                }
            }
            if (boundTable != null)
            {
                foreach (DataGridViewColumn c in dataGridView1.Columns)
                {
                    if (c.IsDataBound)
                    {
                        DataColumn dc = boundTable.Columns[c.DataPropertyName];
                        if (!dc.AllowDBNull && dc.DataType == typeof(string))
                        {
                            c.DefaultCellStyle.DataSourceNullValue = string.Empty;
                            dc.DefaultValue = string.Empty;  // this value is pulled for new rows
                        }
                    }
                }
            }
        }
    }
}

答案 1 :(得分:1)

这似乎是可以接受的解决方案-根据需要进行调整,以消除硬连线的列索引等。

private void dataGridView1_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
{
  var dgv = sender as DataGridView;
  if (null != dgv)
  {
    var row = dgv.Rows[e.RowIndex];
    var drv = row.DataBoundItem as DataRowView;
    if (null != drv)
    {
      var dr = drv.Row as DataSet1.DataTable1Row;
      if (dr.IsNull(0))
      {
        dr.Path = string.Empty;
      }
    }
  }
}

答案 2 :(得分:0)

我遇到了类似的问题,并通过在aspx页面的参数中添加“ ConvertEmptyStringToNull”属性来解决了该问题,

        <UpdateParameters>
            <asp:Parameter Name="myparam" ConvertEmptyStringToNull="false" />
        </UpdateParameters>

这是我的第一个答案,希望可以,它是如此简单,尽管我会发帖帮助其他人进行搜索