【问题标题】:How to prevent blank string from becoming DBNull.Value when DGV is bound to DataTableDGV绑定DataTable时如何防止空字符串变成DBNull.Value
【发布时间】:2019-03-20 21:08:32
【问题描述】:

很难发布代码,但很容易描述如何重现:

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

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

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

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

我尝试过的:

  • 使用 CellEndEdit 处理程序捕获错误值并将其转换为 string.Empty。这确实解决了一些情况(当有多个列时)
  • 使用 CellValidating 处理程序 - 没有帮助
  • 使用 CellFormatting 处理程序 - 没有帮助
  • 使用 CellParsing 处理程序 - 没有帮助
  • 在 BindingSource 上使用 AdditionalNew 处理程序来提供具有非空值的新行 - 没有帮助

还有其他想法吗?

【问题讨论】:

  • 使用 RowValidating 事件处理程序,正如 Google 小组帖子所建议的那样,看起来很有希望。我还尝试使用 DataError 处理程序,它在一定程度上有所帮助(防止错误弹出),但有其他不良视觉效果(导致新行意外消失)。
  • 太棒了 - 请告诉我们你的进展。我通过谷歌搜索找到了nonullallowedexception datagridview blank
  • 感谢您的研究。我没有搜索那个特定的异常(呃!),搜索 DataGridView 和其他术语会产生太多的垃圾,但这个异常是非常具体的。
  • 我通常以相反的方式工作;允许空值并设置列返回一个 string.empty 如果它为空(而不是抛出异常)

标签: c# winforms datagridview


【解决方案1】:

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
                        }
                    }
                }
            }
        }
    }
}

【讨论】:

  • 有趣 - 我不记得读过任何内容说空框被 DGV 视为空值,但显然它在某种程度上。我会检查一下。
  • 是的 - 这行得通。这是一个多一点的工作,但我喜欢它,因为它确实以“正确的方式”解决了问题。太糟糕了,这不是绑定到 DT 的 DGV 的默认行为 - 看起来应该是这样!谢谢。
  • @CarlDaniel,“我不记得读过任何东西……”——至少你尝试过阅读文档。 DGV 的问题在于它做得太多,而且许多(大多数)示例(包括文档中的示例)显示了错误的方法,导致人们感到沮丧和/或声称控制速度很慢。
  • "DGV ... 做的太多了" 当然!自 2002 年以来,我一直在构建 WinForms 应用程序,并且我仍在学习有关 DGV 和数据绑定的新知识。
【解决方案2】:

这看起来是一个可以接受的解决方案 - 根据需要进行调整以摆脱硬连线的列索引等。

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;
      }
    }
  }
}

【讨论】:

    【解决方案3】:

    我有一个类似的问题,并通过在我的 aspx 页面中的参数上添加“ConvertEmptyStringToNull”属性来解决它,就像这样

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

    这是我的第一个答案,所以希望没关系,虽然我会发布以帮助其他人搜索,但它是如此简单

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-02
      相关资源
      最近更新 更多