tab页签切换时,datagridview单元格校验失败,导致datagridview表格无法再进入编辑状态。

Suriyel 2013-06-17 08:14:56
最近在做一个包含了多个tab、表格的复杂控件,遇到了一个很纠结的问题,问题可以简略为以下的demo:

窗体代码

namespace WindowsFormsApplication3
{
partial class Form1
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows 窗体设计器生成的代码

/// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.Column1 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Column2 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Column3 = new System.Windows.Forms.DataGridViewComboBoxColumn();
this.tabControl1.SuspendLayout();
this.tabPage2.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.SuspendLayout();
//
// tabControl1
//
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabControl1.Location = new System.Drawing.Point(0, 0);
this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(284, 262);
this.tabControl1.TabIndex = 0;
//
// tabPage1
//
this.tabPage1.Location = new System.Drawing.Point(4, 22);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(276, 236);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "tabPage1";
this.tabPage1.UseVisualStyleBackColor = true;
//
// tabPage2
//
this.tabPage2.Controls.Add(this.dataGridView1);
this.tabPage2.Location = new System.Drawing.Point(4, 22);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(276, 236);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "tabPage2";
this.tabPage2.UseVisualStyleBackColor = true;
//
// dataGridView1
//
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.Column1,
this.Column2,
this.Column3});
this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
this.dataGridView1.Location = new System.Drawing.Point(3, 3);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.RowTemplate.Height = 23;
this.dataGridView1.Size = new System.Drawing.Size(270, 230);
this.dataGridView1.TabIndex = 0;
this.dataGridView1.CellValidating += new System.Windows.Forms.DataGridViewCellValidatingEventHandler(this.dataGridView1_CellValidating);
//
// Column1
//
this.Column1.HeaderText = "Column1";
this.Column1.Name = "Column1";
//
// Column2
//
this.Column2.HeaderText = "Column2";
this.Column2.Name = "Column2";
//
// Column3
//
this.Column3.HeaderText = "Column3";
this.Column3.Items.AddRange(new object[] {
"hello1",
"hello2"});
this.Column3.Name = "Column3";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 262);
this.Controls.Add(this.tabControl1);
this.Name = "Form1";
this.Text = "Form1";
this.tabControl1.ResumeLayout(false);
this.tabPage2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
this.ResumeLayout(false);

}

#endregion

private System.Windows.Forms.TabControl tabControl1;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.DataGridView dataGridView1;
private System.Windows.Forms.DataGridViewTextBoxColumn Column1;
private System.Windows.Forms.DataGridViewTextBoxColumn Column2;
private System.Windows.Forms.DataGridViewComboBoxColumn Column3;
}
}






using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
if(e.ColumnIndex==-1||e.RowIndex==-1)
{
return;
}
if(string.IsNullOrEmpty(e.FormattedValue.ToString()))
{
return;
}
int value = 0;
if(!int.TryParse(e.FormattedValue.ToString(),out value))
{
e.Cancel = true;
dataGridView1.CancelEdit();
MessageBox.Show(this, "Erro Data.");
}
}
}
}





描述:一个很简单的窗体,包含一个tab及表格,后台逻辑就是如果输入是非数字,触发cellValidate校验,并做提示。
问题复现步骤:
1,打开窗体
2,切换到第二页签,在column1上输入一个非数字字符,然后直接点击tabPage1。出现结果1.
实际结果:
1,提示校验“Data Erro.”
点击column3,下拉选项无法显示,再点击column1,column2,无法进入编辑状态,但是可以直接输值。
期望结果:
点击column3能够选择下拉选项,点击column1,column2能够进入编辑状态。


特别注明:
1,希望在切换tab时,如果表格校验非法,需要提示并留在当前tabpage。
因为实际场景中,表格校验很复杂,分了cell和row两种校验,需要先保证cell校验是合法的,不然row校验会崩溃,所以必须触发cellvalidate,所以CausesValidation需要设置为true。
2,上述后台代码,如果去掉
MessageBox.Show(this, "Erro Data.");
那么不会出现上面那个问题。(所以说是微软的一个bug???)
...全文
422 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
allensmith2 2015-01-28
  • 打赏
  • 举报
回复
实现DataGridView控件中验证数据输入功能主要是利用DataGridView控件的公共事件CellValidating和CellEndEdit事件在为当前选定的单元格停止编辑模式时发生。本实例判断控件第一列中单元格的值是否为空。在CellValidating事件中进行验证,如果严重失败,将System.Windows.Forms.DataGridViewCellValidatingEventArgs类的Cancel属性设置为True。这将导致DataGridView控件阻止光标离开该单元格。将该行的ErrorText属性设置为解释性字符串,将显示错误图标,其工具提示将保护此错误文本。在CellEndEdit事件处理程序中,将该行的ErrorText属性设置为空字符串。只有当单元格退出编辑模式(如果验证失败,则不能退出单元格)时,才能发生CellEndEdit事件。运动程序,编辑控件的第一列,在单元格中不输入内容,然后使用鼠标单击其他单元格,这样就会提示错误 下面给出大家主要代码: Private void dataGridView1_CellValidating(object sender,DataGridViewCellValidatingEventArgs e) { If (e.ColumnIndex==0) { If(String.IsNullOrEmpty(e.FormattedValue.ToString)) { dataGridView1.Rows[e.RowIndex].ErrorText=”单元格第一列值不能为空”; e.Cancel=true; } } } Private void dataGridView1_CellEndEdit(object sender,DataGridViewCellEventArgs e) { dataGridView1.Rows[e.RowIndex].ErrorText=String.Empty; } __________________________________________________________________________________________ draw code128 in c#.net draw code128 in c#.net
yixian2007 2014-05-23
  • 打赏
  • 举报
回复
都这么久都没结贴,楼主不厚道。
DENQH 2013-07-27
  • 打赏
  • 举报
回复
切换时加个判断if(dataGri1.DataSource!=null) { .................................... }
Suriyel 2013-07-27
  • 打赏
  • 举报
回复
引用 14 楼 czz65979674 的回复:
其实这个无非是想让第2个TAB里面的GRID里不能输入非数字是吧,做的方法很多 一,像楼上那样做个隐藏的TEXT 绑定列。 二,不采用你原先的cellvalidate 而是用cellbeginedit,来判断它是否进入编辑状态,返回一个布尔值,然后在这个GRID的keydown事件里 截取按键 这样可以实现 非数字键都无法输入 三,如果设计式样允许,做个小型子页面,这个画面的CELL是不可编辑的,双击CELL弹出子画面,子画面的TEXTBOX等 进行赋值
就用户体验感,来说第二种要比第三种要好 第二种是可行的,但是有个问题,就是将校验耦合到了view控件层,不利于校验逻辑或该控件的复用
yixian2007 2013-07-12
  • 打赏
  • 举报
回复
引用 12 楼 Suriyel 的回复:
[quote=引用 11 楼 yixian2007 的回复:] [quote=引用 10 楼 osnot 的回复:] [quote=引用 9 楼 yixian2007 的回复:] 不使用e.cancel = true就行了。 [quote=引用 8 楼 osnot 的回复:] [quote=引用 7 楼 yixian2007 的回复:] 唔,我会的,也遇到过这种问题,不过你解决了就算了。
请问你怎么解决的?[/quote][/quote] 不用e.cancel = true会有问题的。[/quote] 啥问题,你提示他错了,然后把它输入的值置为一个默认的合法值就行了,或者设定为空值。你使用e.cancel就把后续的所有操作全停了。[/quote] e.Cancel不赋值的话,正常的cell校验就失效了[/quote] 既然你如此纠结,告诉你个终极的解决方法,自定义列,将列自定义,这样当进入编辑模式时,进入的是自定义的控件,不使用datagridview的验证了,直接在textbox中验证。验证不通过不离开textbox,这样的情况连datagridview都回不到,更别提点什么tab了。 其实正常的校验你不理它就可以了,给他个提示错误,然后重置,正常的校验怎么不行?
czz65979674 2013-07-12
  • 打赏
  • 举报
回复
其实这个无非是想让第2个TAB里面的GRID里不能输入非数字是吧,做的方法很多 一,像楼上那样做个隐藏的TEXT 绑定列。 二,不采用你原先的cellvalidate 而是用cellbeginedit,来判断它是否进入编辑状态,返回一个布尔值,然后在这个GRID的keydown事件里 截取按键 这样可以实现 非数字键都无法输入 三,如果设计式样允许,做个小型子页面,这个画面的CELL是不可编辑的,双击CELL弹出子画面,子画面的TEXTBOX等 进行赋值
Suriyel 2013-07-08
  • 打赏
  • 举报
回复
引用 11 楼 yixian2007 的回复:
[quote=引用 10 楼 osnot 的回复:] [quote=引用 9 楼 yixian2007 的回复:] 不使用e.cancel = true就行了。 [quote=引用 8 楼 osnot 的回复:] [quote=引用 7 楼 yixian2007 的回复:] 唔,我会的,也遇到过这种问题,不过你解决了就算了。
请问你怎么解决的?[/quote][/quote] 不用e.cancel = true会有问题的。[/quote] 啥问题,你提示他错了,然后把它输入的值置为一个默认的合法值就行了,或者设定为空值。你使用e.cancel就把后续的所有操作全停了。[/quote] e.Cancel不赋值的话,正常的cell校验就失效了
yixian2007 2013-07-07
  • 打赏
  • 举报
回复
引用 10 楼 osnot 的回复:
[quote=引用 9 楼 yixian2007 的回复:] 不使用e.cancel = true就行了。 [quote=引用 8 楼 osnot 的回复:] [quote=引用 7 楼 yixian2007 的回复:] 唔,我会的,也遇到过这种问题,不过你解决了就算了。
请问你怎么解决的?[/quote][/quote] 不用e.cancel = true会有问题的。[/quote] 啥问题,你提示他错了,然后把它输入的值置为一个默认的合法值就行了,或者设定为空值。你使用e.cancel就把后续的所有操作全停了。
yixian2007 2013-07-05
  • 打赏
  • 举报
回复
不使用e.cancel = true就行了。
引用 8 楼 osnot 的回复:
[quote=引用 7 楼 yixian2007 的回复:] 唔,我会的,也遇到过这种问题,不过你解决了就算了。
请问你怎么解决的?[/quote]
osnot 2013-07-05
  • 打赏
  • 举报
回复
引用 9 楼 yixian2007 的回复:
不使用e.cancel = true就行了。 [quote=引用 8 楼 osnot 的回复:] [quote=引用 7 楼 yixian2007 的回复:] 唔,我会的,也遇到过这种问题,不过你解决了就算了。
请问你怎么解决的?[/quote][/quote] 不用e.cancel = true会有问题的。
osnot 2013-07-04
  • 打赏
  • 举报
回复
引用 7 楼 yixian2007 的回复:
唔,我会的,也遇到过这种问题,不过你解决了就算了。
请问你怎么解决的?
Suriyel 2013-07-02
  • 打赏
  • 举报
回复
引用 5 楼 osnot 的回复:
上面的代码有问题:当输入完非数字后,我点击另外一个cell,这时会弹出提示对话框,然后我点击第一个tab是没有反应的,因为isDataGridViewValidateError = true;我又查了很多文档,终于利用关键字:datagridview CellValidating tabControl 在google上搜索到了:http://social.msdn.microsoft.com/Forums/en-US/winformsdatacontrols/thread/c3634471-49cb-4274-afa4-c4bcd184b52c 在2009/02/19号就有人在MSDN上提交这个Bug了,MSDN回复说:已经反馈给开发小组,可是现在还是这样,应该是MS的一个Bug。 如果有解决方法,记得通知我。 谢谢。
已经解决了 http://www.cnblogs.com/suriyel/p/3166086.html
yixian2007 2013-07-02
  • 打赏
  • 举报
回复
唔,我会的,也遇到过这种问题,不过你解决了就算了。
osnot 2013-06-18
  • 打赏
  • 举报
回复
抱歉,昨天太懒了,没有写代码。今天写了一点代码,刚开始以为是TabControl的问题,后来测试发现是DataGridView的问题,以为弹出一个对话框后,DataGridView可能会失去焦点,或者编辑模式变了,后来发现没有变,再后来发现还是TabControl的问题,因为它实际已经激活了另外一个选项卡,但是画面时停留在现在(包含GridView的选项卡),所以导致了这个问题,解决方法和Silverlight一样。。。 代码(Form1.Designer.cs)-增加了tabControl1.Deselecting事件:

...
this.tabControl1.Deselecting += new System.Windows.Forms.TabControlCancelEventHandler(this.tabControl1_Deselecting);
...
然后后台cs文件:

public partial class Form1 : Form
    {
        private bool isDataGridViewValidateError = false;

        public Form1()
        {
            InitializeComponent();
        }

        private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            if(e.ColumnIndex==-1||e.RowIndex==-1)
            {
                return;
            }
            if(string.IsNullOrEmpty(e.FormattedValue.ToString()))
            {
                return;
            }
            int value = 0;
            if(!int.TryParse(e.FormattedValue.ToString(),out value))
            {
                //e.Cancel = true;
                dataGridView1.CancelEdit();
                MessageBox.Show(this, "Erro Data.");
                isDataGridViewValidateError = true;
            }
        }

        private void tabControl1_Deselecting(object sender, TabControlCancelEventArgs e)
        {
            if (isDataGridViewValidateError == true)
            {
                e.Cancel = true;
                isDataGridViewValidateError = false;
            }
        }
    }
如上面代码,把e.Cancel = true;注掉了,因为如果设置为true的话,就不会出发TabContorl的切换事件,而实际已经切换过去了,所以会出问题,解决办法是在这个事件中取消切换。 测试通过,希望帮到你。
osnot 2013-06-18
  • 打赏
  • 举报
回复
上面的代码有问题:当输入完非数字后,我点击另外一个cell,这时会弹出提示对话框,然后我点击第一个tab是没有反应的,因为isDataGridViewValidateError = true;我又查了很多文档,终于利用关键字:datagridview CellValidating tabControl 在google上搜索到了:http://social.msdn.microsoft.com/Forums/en-US/winformsdatacontrols/thread/c3634471-49cb-4274-afa4-c4bcd184b52c 在2009/02/19号就有人在MSDN上提交这个Bug了,MSDN回复说:已经反馈给开发小组,可是现在还是这样,应该是MS的一个Bug。 如果有解决方法,记得通知我。 谢谢。
Suriyel 2013-06-17
  • 打赏
  • 举报
回复
木有人晓得么,100分哦,混分的都没一个咩
Suriyel 2013-06-17
  • 打赏
  • 举报
回复
引用 1 楼 osnot 的回复:
遇到过类似的问题,不过当时是Silverlight的,不知道WinForm的事件和方法是否一致。 当时问题是:tab1里面有输入框,需要验证,如果输入内容,并且直接点击tab2,则会跳转到tab2,并且会弹出:输入错误框。 解决方法:添加Tab的切换事件,并且定义Flag:IsAllowChangTab(是否需要切换tab),如果验证不通过则设置为false,然后在Tab的切换事件中,判断IsAllowChangTab,如果是false,则再次切换到原来的Tab。 没有找到更好的方法,当然这是在Silverlight中,而且验证事件在切换事件前,希望帮到你。
谢谢,不过我并不是切换不了的问题。
osnot 2013-06-17
  • 打赏
  • 举报
回复
遇到过类似的问题,不过当时是Silverlight的,不知道WinForm的事件和方法是否一致。 当时问题是:tab1里面有输入框,需要验证,如果输入内容,并且直接点击tab2,则会跳转到tab2,并且会弹出:输入错误框。 解决方法:添加Tab的切换事件,并且定义Flag:IsAllowChangTab(是否需要切换tab),如果验证不通过则设置为false,然后在Tab的切换事件中,判断IsAllowChangTab,如果是false,则再次切换到原来的Tab。 没有找到更好的方法,当然这是在Silverlight中,而且验证事件在切换事件前,希望帮到你。
vb.net操作DataGridView控件的用法的集合,包括: 1. DataGridView当前的单元格属性取得、变更 2. DataGridView编辑属性 3. DataGridView最下面一列新追加行非表示 4. DataGridView判断当前选中行是否为新追加的行 5. DataGridView删除行可否设定 6. DataGridView行列不表示和删除 DataGridView控件用法合集(二) 7. DataGridView行列宽度高度设置为不能编辑 8. DataGridView行高列幅自动调整 9. DataGridView指定行列冻结 10. DataGridView列顺序变更可否设定 11. DataGridView行复数选择 12. DataGridView选择的行、列、单元格取得 DataGridView控件用法合集(三) 13. DataGridView指定单元格是否表示 14. DataGridView表头部单元格取得 15. DataGridView表头部单元格文字列设定 16. DataGridView选择的部分拷贝至剪贴板 17.DataGridView粘贴 18. DataGridView单元格上ToolTip表示设定(鼠标移动到相应单元格,弹出说明信息) DataGridView控件用法合集(四) 19. DataGridView中的ContextMenuStrip属性 20. DataGridView指定滚动框位置 21. DataGridView手动追加列 22. DataGridView全体分界线样式设置 23. DataGridView根据单元格属性更改显示内容 24. DataGridView新追加行的行高样式设置る 25. DataGridView新追加行单元格默认值设置 DataGridView中输入错误数据的处理(五) 26. DataGridView单元格数据错误标表示 27. DataGridView单元格内输入值正确性判断 28. DataGridView单元格输入错误值事件的捕获 DataGridView控件用法合集(六) 29. DataGridView行排序(点击列表头自动排序的设置) 30. DataGridView自动行排序(新追加值也会自动排序) 31. DataGridView自动行排序禁止情况下的排序 32. DataGridView指定列指定排序 DataGridView控件用法合集(七) 33. DataGridView单元格样式设置 34. DataGridView文字表示位置的设定 35. DataGridView单元格内文字列换行 36. DataGridView单元格DBNull值表示的设定 37. DataGridView单元格样式格式化 38. DataGridView指定单元格颜色设定 39. DataGridView单元格文字字体设置 40. DataGridView根据单元格值设定单元格样式 DataGridView控件用法合集(八) 41. DataGridView设置单元格背景颜色 42. DataGridView行样式描画 43. DataGridView显示行号 44. DataGridView焦点所在单元格焦点框不显示的设定 DataGridView控件用法合集(九) 45. DataGridView中显示选择框CheckBox 46. DataGridView中显示下拉框ComboBox 47. DataGridView单击打开下拉框 48. DataGridView中显示按钮 49. DataGridView中显示链接 50. DataGridView中显示图像 DataGridView控件用法合集(十) 51. DataGridView编辑单元格控件取得 52. DataGridView输入自动完成 53. DataGridView单元格编辑键盘KEY事件取得 54. DataGridView下拉框(ComboBox)单元格编辑事件取得 55. DataGridView下拉框(ComboBox)单元格允许文字输入设定 DataGridView控件用法合集(十一) 56. DataGridView根据值不同在另一列中显示相应图片 57. DataGridView中显示进度条(ProgressBar) 58. DataGridView中添加MaskedTextBox DataGridView控件用法合集(十二) 59. DataGridView中Enter键按下焦点移至旁边的单元格 60. DataGridView行集合化(Group)

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧