最近在做一个包含了多个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会有问题的。
------解决思路----------------------
不使用e.cancel = true就行了。
唔,我会的,也遇到过这种问题,不过你解决了就算了。
请问你怎么解决的?
不用e.cancel = true会有问题的。
啥问题,你提示他错了,然后把它输入的值置为一个默认的合法值就行了,或者设定为空值。你使用e.cancel就把后续的所有操作全停了。
------解决思路----------------------
不使用e.cancel = true就行了。
唔,我会的,也遇到过这种问题,不过你解决了就算了。
请问你怎么解决的?
不用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)
{
....................................
}
------解决思路----------------------
都这么久都没结贴,楼主不厚道。