【问题标题】:Validating a Cell input before the bound object is updated [closed]在更新绑定对象之前验证单元格输入[关闭]
【发布时间】:2021-01-30 05:25:04
【问题描述】:

我使用 BindingList 将对象绑定到 DataGridView。

我需要在底层绑定对象属性更新之前验证键入单元格的数据。

我正在尝试使用CellValidating 事件,但我设置了断点,并且绑定对象的属性在CellValidating 之前获得了新值。

我正在寻找类似CellBeforeUpdate 的事件,但该事件在此网格中不存在。

我是否遗漏了一些明显的东西?

{编辑,这是一个编程错误。我插入了一个将索引移动 1 的列,并且 CellValidating 事件中的代码正在查看不正确的注释。

我认为更好的做法是使用列名而不是索引来避免这样的错误}

【问题讨论】:

  • 你能发布你的代码吗?或者您尝试过但似乎不起作用的方法。
  • 通常的顺序是CellValidating、CellValueChanged、CellValidated、CellEndEdit。在CellValidating 中,底层数据对象不变。
  • 没有太多可以粘贴的代码有帮助。我有一个绑定到 datagridview 的 BindingList。我有一个单元格列 ItemCode,它绑定到 Bindinglist 中对象的 ItemCode 属性。我在属性设置器中放置了一个断点,当我编辑单元格时,它会在 CellValidating 事件触发之前命中设置器断点。
  • 我很抱歉浪费了大家的时间。这是一个编程错误。我使用索引而不是列名来访问该列,并且我在前面添加了一个列,它将所有索引移动了一个。 Cellvalidating 事件在设置 之后触发,因为它是针对不同列的,该列根据在相关列中输入的值更新数据。我的错。

标签: c# winforms datagridview


【解决方案1】:

我不同意你的评论……

”绑定对象的属性获取之前的新值 CellValidating 可以。” …

在执行“离开”网格CellValidating 事件之前,底层数据源不会改变。

在CellValidating 事件的开头放置一个断点。然后运行代码,对网格中的一个单元格进行更改,然后尝试离开该单元格。当断点命中时,查看底层数据源。它不会显示网格单元格中的更改。

由于您没有显示代码,我只能假设在CellValidating 事件中,有“某种”检查来验证单元格中的数据是否无效。您如何检查这是未知的,我们只能假设您检查的是正确的值。

但是,无论如何,如果您检查单元格中的值并确定它是无效值,并希望在编辑“之前”将单元格值设置为其原始值,则调用网格CancelEdit() 方法应该为你做这个。像……

private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
  if (e.FormattedValue.ToString() == "some invalid value") {
    dataGridView1.CancelEdit();
  }
}

编辑…

为了提供帮助,我能做的最好的事情就是证明你所说的正在发生……不能用给定的信息重现。

据我所知……

  1. 网格使用BindingList<T> 作为网格的DataSource。

  2. 不知道“T”是什么,我们只能猜测它是一个基本类。

  3. 网格已订阅(连接)其CellValidating 事件。

现在,如果我们尝试重现此...“基本”类可能如下所示,其中该类的一个 int 属性根据您的评论命名为“ItemCode”。此外,还添加了一个名为“ItemName”的附加 string 属性。尽可能基本......

public class ItemClass {
  public int ItemCode { get; set; }
  public string ItemName { get; set; }
}

为了提供帮助,我们将创建一个 GetData 方法,该方法返回一个包含 15 个 ItemClass 对象的 BindingList<ItemClass>。我们将使用这个绑定列表作为网格的数据源。

private BindingList<ItemClass> GetData() {
  BindingList<ItemClass> bl = new BindingList<ItemClass>();
  for (int i = 1; i < 16; i++) {
    bl.Add(new ItemClass { ItemCode = i, ItemName = "Item " + i });
  }
  return bl;
}

接下来,我们需要连接网格CellValidating 事件。在此示例中,由于ItemCode 是int 值,CellValidating 事件将是检查并确保用户在单元格中键入有效int 值的好地方。否则,用户可能会键入字符并抛出网格DataError. 在此示例中,如果文本不是有效的int 值,则单元格的值将返回到编辑前的原始值。

这给了我们一个很好的理由来连接这个事件,但它也很方便,所以当用户“更改”单元格值时,我们可以检查BindingList&lt;ItemClass&gt; 列表中的值。

private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
  if (e.ColumnIndex == 0) {
    if (!int.TryParse(e.FormattedValue.ToString(), out int value)) {
      dataGridView1.CancelEdit();
    }
  }
}

因此,创建一个新的 winforms 项目并将 DataGridView 拖放到表单上。除了上面的代码,我们唯一需要的代码如下……

BindingList<ItemClass> GridBindingList;

public Form2() {
  InitializeComponent();
}

private void Form2_Load(object sender, EventArgs e) {
  GridBindingList = GetData();
  dataGridView1.DataSource = GridBindingList;
}

我们创建了一个“全局”变量GridBindingList,这样我们就可以在我们设置的任何断点检查它的值。在表单Load 事件中,GridBindingList 填充了测试数据,最后将网格DataSource 设置为此绑定列表。

这是我能破译的最接近你的代码,因为你拒绝显示它。

您声明当用户在网格中的单元格中键入文本然后尝试离开该单元格时……GridBindingList 将使用网格单元格中的文本“在”调用网格CellValidating 事件之前进行更新.

我坚持我的评论,您对此有误。使用上面的代码,你应该可以自己测试一下。

当执行时,上面的代码应该会产生类似于左边表格的东西……

编辑网格中的第二个项目后,它可能看起来像右边的表格......

然后离开单元格,网格CellValidating 事件触发。遇到断点并在事件的第一行停止执行,如下所示。

如图所示,GridBindingList 的第二项还没有像您所说的那样发生变化。此外,在观察列表下方,我们可以看到格式化值“fsdgfdgdf”仍然显示在网格中。

您能否提供重现您所描述内容的代码?从你的评论到这个答案……

“我在底层对象的属性中设置了断点,它在 CellValidating 事件之前 100% 触发。” ...

然后“显示”一个例子。我希望这个例子能证明底层数据源在网格CellValidating 事件触发之前不会改变。

【讨论】:

  • @Kim... 然后显示您可以重新生成此内容的代码。我使用DataTable 作为数据源的测试不符合您的描述。如果没有一些代码来重现您的问题,我们所拥有的只是您的话。从我的测试来看,你所说的不正确。请展示您所描述内容的示例,以便我们可以复制和粘贴以重现问题。如果没有示例,我们只能猜测“为什么”我们会得到不同的结果。
  • 我很抱歉浪费了大家的时间。这是一个编程错误。我使用索引而不是列名来访问该列,并且我在前面添加了一个列,它将所有索引移动了一个。 Cellvalidating 事件在 setter after 之后触发,因为它针对的是不同的列,该列正在根据在相关列中输入的值更新数据。我的错。
猜你喜欢
  • 2021-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-12
相关资源
最近更新 更多