当前位置: 代码迷 >> C# >> tab页签切换时,datagridview单元格校验失败,招致datagridview表格无法再进入编辑状态
  详细解决方案

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

热度:55   发布时间:2016-05-05 04:57:48.0
tab页签切换时,datagridview单元格校验失败,导致datagridview表格无法再进入编辑状态。
本帖最后由 Suriyel 于 2013-06-17 20:19:36 编辑
最近在做一个包含了多个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???)
------解决思路----------------------
引用:
不使用e.cancel = true就行了。

Quote: 引用:

Quote: 引用:

唔,我会的,也遇到过这种问题,不过你解决了就算了。

请问你怎么解决的?

不用e.cancel = true会有问题的。
------解决思路----------------------
引用:
Quote: 引用:

不使用e.cancel = true就行了。

Quote: 引用:

Quote: 引用:

唔,我会的,也遇到过这种问题,不过你解决了就算了。

请问你怎么解决的?

不用e.cancel = true会有问题的。


啥问题,你提示他错了,然后把它输入的值置为一个默认的合法值就行了,或者设定为空值。你使用e.cancel就把后续的所有操作全停了。
------解决思路----------------------
引用:
Quote: 引用:

Quote: 引用:

Quote: 引用:

不使用e.cancel = true就行了。

Quote: 引用:

Quote: 引用:

唔,我会的,也遇到过这种问题,不过你解决了就算了。

请问你怎么解决的?

不用e.cancel = true会有问题的。


啥问题,你提示他错了,然后把它输入的值置为一个默认的合法值就行了,或者设定为空值。你使用e.cancel就把后续的所有操作全停了。




e.Cancel不赋值的话,正常的cell校验就失效了


既然你如此纠结,告诉你个终极的解决方法,自定义列,将列自定义,这样当进入编辑模式时,进入的是自定义的控件,不使用datagridview的验证了,直接在textbox中验证。验证不通过不离开textbox,这样的情况连datagridview都回不到,更别提点什么tab了。
其实正常的校验你不理它就可以了,给他个提示错误,然后重置,正常的校验怎么不行?
------解决思路----------------------
其实这个无非是想让第2个TAB里面的GRID里不能输入非数字是吧,做的方法很多
一,像楼上那样做个隐藏的TEXT 绑定列。
二,不采用你原先的cellvalidate 而是用cellbeginedit,来判断它是否进入编辑状态,返回一个布尔值,然后在这个GRID的keydown事件里 截取按键 这样可以实现 非数字键都无法输入
三,如果设计式样允许,做个小型子页面,这个画面的CELL是不可编辑的,双击CELL弹出子画面,子画面的TEXTBOX等 进行赋值 
------解决思路----------------------
切换时加个判断if(dataGri1.DataSource!=null)
{
....................................
}
------解决思路----------------------
都这么久都没结贴,楼主不厚道。
  相关解决方案