今天在编写代码的时候碰到了控件的验证问题。
命题:在前台的DataGridView中,任意行的单元格都不能为空,也就是说,在编写的过程中,某一行的编辑完成之后,需要验证各单元是否为空。
事件绑定:最开始编写的时候,我调用了dgvDetail.RowLeave事件。发现每次鼠标移到其他行的时候,最后一个编写的单元数据还没有写入之前就开始执行RowLeave事件了。也就是说,用户已经填写了数据,但是在数据写入控件之间就先执行验证事件了。这样的操作过程对用户来讲是非常不友好的。
然后我做了一个调整,将验证事件绑在了dgvDetail.RowValidated上。
随后我做了一个控件事件的发生顺序以及赋值情况的测试。
测试对象:TextBox、DataGridView.前台窗口如下:
后台代码如下:
public partial class TestEvent : Form { string txtEventStr = "", dgvEventStr = ""; int txtI = 0, dgvI = 0; public TestEvent() { InitializeComponent(); Action<string> txtAdd = txt => { txtI++; txtEventStr += string.Format("\r\n{0}:{1}, Text = {2}", txtI, txt, txtEventTest.Text); }; Action<string> dgvStrAdd = txt => { dgvI++; dgvEventStr += string.Format("\r\n{0}:{1}, Text = {2}", dgvI, txt, dgv[0, 0].Value); }; txtEventTest.Validated += (a, b) => txtAdd("Validated"); txtEventTest.Validating += (a, b) => txtAdd("Validating"); txtEventTest.Leave += (a, b) => txtAdd("Leave"); txtEventTest.LostFocus += (a, b) => txtAdd("LostFocus"); txtEventTest.GotFocus += (a, b) => txtAdd("GotFocus"); txtEventTest.Enter += (a, b) => txtAdd("Enter"); btnTxtEvent.Click += (a, b) => MessageBox.Show(txtEventStr); dgv.RowEnter += (a, b) => dgvStrAdd("RowEnter"); dgv.RowValidated += (a, b) => dgvStrAdd("RowValidated"); dgv.RowValidating += (a, b) => dgvStrAdd("RowValidating"); dgv.RowLeave += (a, b) => dgvStrAdd("RowLeave"); btnDGVEvent.Click += (a, b) => MessageBox.Show(dgvEventStr); } }
前台操作:
鼠标点击textbox => 输入文字 => 点击按钮btnTxtEvent。
鼠标点击dgv的[0,0]单元 => 输入文字 => 点击按钮btnDGVEvent。
执行结果:
根据最后的执行结果,我们可以清晰的看到textBox的事件执行顺序为Enter、GotFocus、LostFocus、Leave、Validating、Validated,也就是说程序先“进入”控件,然后控件“得到焦点”,紧接着控件“失去焦点”,此时前台输入的值已经写入控件属性,然后“离开”控件,开始“校验”,最后发生“校验完”事件。
而DataGridView的行事件执行顺序为RowEnter、RowLeave、RowValidating、RowValidated,顺序与textBox的事件执行顺序可以说一致,但有一个很大的区别,前台输入值写入控件的时间。相较于textbox在Leave事件之前就写入,DataGridView却是在RowLeave事件之后才写入控件的属性。因此,回到最开始的命题中,才会导致那样不友好的操作结果。
以上内容为笔者亲著,转发请注明本文地址:
http://www.cnblogs.com/icyJ/archive/2012/10/29/Event_Order.html