工具栏ToolStrip能触发焦点控件的Leave、Validating、DataError等事件以验证数据 z

public class ToolStripEx : ToolStrip
{
    protected override void OnClick(EventArgs e)
    {
        base.OnClick(e);
        Form fm = FindForm();
        if (fm != null) { fm.Validate(); }
    }
}

之所以说几乎,是因为还是有一点不同,就是Form.Validate()并不会触发焦点控件的Leave事件,所以需要该事件的猿友恐怕还得继续沿用0尺寸Button法或另想他法。

另外发现ToolStrip还有个操蛋的问题,就是上述方法都只对 ToolStripButton的Click事件有效,但如果按钮是分离按钮ToolStripSplitButton,大家知道,按钮部分的单击事件就 该用ButtonClick而不是Click,单击按钮部分虽然也会先触发ToolStrip.Click事件进行验证,但不管验证结果如 何,ButtonClick都会被执行,不像ToolStripButton.Click那样,验证不过就不会执行。所以对付ButtonClick,在 找到更好的办法前,我还得在事件处理方法中加判断才行。真他娘的让人不省心。

----------------原文:2014-03-24---------------

如题,Winform码农大概都知道这样一个问题,就是当输入焦点仍处在 TextBox、DataGridViewCell等控件中时,如果单击普通Button、CheckBox等控件,那么该验证的会得到验证,该提交的会 提交,该报错的会报错,该被阻止的操作会被阻止。但如果单击的是工具栏上的项目(如ToolStripButton,之所以说项目而不是控件,你懂的), 是不会触发焦点控件的验证事件的,而是会直接执行按钮事件,这样带来的影响相信大家深有体会。总之不解决ToolStrip的这个问题我不会幸福。先看办 法:

/// <summary>
/// 工具栏(无右侧竖线、无手柄、可触发其它控件验证)
/// </summary>
public class ToolStripEx : ToolStrip
{
    readonly Button btn;//定义一个用来转移焦点的控件,如Button

    public ToolStripEx()
    {
        //初始化并指定控件尺寸为0,0。因为你不会希望这个按钮被看到
        btn = new Button { Width = 0, Height = 0 };

        //下面为可选项
        //让工具栏在视觉上更地道。如被按下的ToolStripButton更明显,否则只有一个惨淡的线框
        ToolStripManager.VisualStylesEnabled = false;

        //不显示拖曳抓柄
        GripStyle = ToolStripGripStyle.Hidden;
    }

    //在工具栏获得句柄后将控件添加进窗体,之所以不在构造函数中做这事是因为那个时候窗体也许还是null
    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);
        Form fm = this.FindForm();
        if (fm != null) { fm.Controls.Add(btn); }//这样添加后,btn.Location会是0,0
    }

    //在工具栏被碰到时(其实选用其它类似事件也行)将焦点转移到btn上,以此触发焦点控件的验证
    //注意虽然是工具栏的Click,但经过实践点击其中的子项都会优先触发该事件
    //所以当焦点控件验证通不过时,不会再执行子项的Click事件,这一点我想是由win32消息机制实现的
    protected override void OnClick(EventArgs e)
    {
        base.OnClick(e);
        btn.Focus();
    }

    //可选。把工具栏最右边的1px竖线K掉,这种瑕疵对于我来说简直不能忍受,草泥马微软,有病
    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.SetClip(new Rectangle(0, 0, Width - 1, Height));
        base.OnPaint(e);
    }
}

办法很简单,就是在点击工具栏时先把焦点移到其它能正常获得焦点的控件上,以此来触发先前控件的Leave/Validating/DataError等事件。

其实为了解决这个问题我颇费了一番周折,最开始想到的其实就是这招,但觉得猥琐了 点,作为一个有追求的码农,我认为应该从消息层面去解决,所以一开始就把这个阴招放在一边,专心捣鼓消息。开始我认为这个问题的本质是因为,工具栏就像 Panel之类的控件,是得不到焦点的控件,不像Button之流,能够让其他控件的焦点转移过来,所以才有这个问题。那么我就想通过调用win32 API,让工具栏能发出与Button一样的消息,让焦点控件受骗,以为点到的是Button,从而验证自己的数据,移交自己的焦点。经过多番实践,确实 让工具栏获得了焦点,让焦点控件失去焦点,用Spy++看焦点控件接收到的消息也与点击Button接收到的消息看起来一样了,但仍然不会触发验证,这就 扯蛋了~我那个沮丧啊。BTW~其实给工具栏设置SetStyle(ControlStyles.Selectable, true)也可以达到同样目的,但一样解决不了问题。

也许是还没摸透问题的本质,也许是win32消息还是玩不转~总之是经历过若干次失败的尝试,我不得不放弃高大上的解决办法,这才回头来重新拾起猥琐方案,所以文中办法其实是妥协的结果,难免心有不甘,等他日机缘到了,我定再次尝试“正统”的解决办法。

时间: 2024-07-31 19:26:13

工具栏ToolStrip能触发焦点控件的Leave、Validating、DataError等事件以验证数据 z的相关文章

在asp.net页面上按回车会触发Imagebutton控件的Click事件

原文:在asp.net页面上按回车会触发Imagebutton控件的Click事件 问题: 用asp.net做的aspx页面,无论是否有文本框.下拉框.复选框……获得焦点,只要在当前页面上按一下回车就会触发该页面上的第一个Imagebutton控件的Click事件. 原因: 在form表单内部如果出现了input type="image"或者input type="submit"这些控件,都会自动接收表单上的回车事件 方案: 在页面上放2个imagebutton,第

js代码赋值触发select控件的onchange事件

嗯,现在在一个小公司实习,直接接触代码收获不小.  现在有个需求是4级联动的select过滤,需要js代码赋值并触发onchange来调用ajax方法,于是问题是怎样触发,找了些资料并且自己尝试了一下,验证无误. 代码在chrome.IE8.ff浏览器测试均通过,记在这里以备查阅~ <html> <head> </head> <body> <select id="sel" name="mysel" onchang

在GridView控件内文本框实现TextChanged事件

本篇是教你实现GridView控件内的TextBox文本框实现自身的TextChanged事件.由于某些功能的需求,GridView控件内嵌TextBox,当TextBox值发生变化时,触发TextChanged事件. 在.aspx网页内,Insus.NET尝试写一个GridView,算了,我们还想在Ajax环境之下运行: 为了实现TextChanged事件,得需要在GridView控件中写OnRowCreated事件,记住是OnRowCreated事件,而不是OnRowDataBound事件.

c#中如何保存焦点控件?

对所有文本框添加焦点获得事件,头部再定义一个全局的object或者control的类型对象,在焦点获得事件中把当前控件对象赋值给之前定义的object或者control对象,操作的话就对这个全局量操作就可以了. public partial class ExTextBox: TextBox { public static  Control control; public ExTextBox() { InitializeComponent(); } protected override void

VS2012或VS2010 工具栏中无法显示DevExpress控件

进入命令提示符 跳转到Dev控件安装目录,如[目录D:\Program Files (x86)\DevExpress\DXperience 12.2\Tools]下, 然后执行命令: ToolboxCreator.exe /ini:toolboxcreator.ini 如果要删除控件,则执行命令: ToolboxCreator.exe /ini:toolboxcreator.ini /remove

[iOS基础控件 - 6.11.3] 私人通讯录Demo 控制器的数据传递、存储

A.需求 1.搭建一个“私人通讯录”Demo 2.模拟登陆界面 账号 密码 记住密码开关 自动登陆开关 登陆按钮 3.退出注销 4.增删改查 5.恢复数据(取消修改) B.基本架构 1. 5个控制器 (1)导航控制器 NavigationController (2)登陆 UIViewController 输入账号密码 记住密码.自动登录开关 登陆跳转按钮 (3)联系人列表 TableViewController 注销功能 添加联系人跳转按钮 (4)添加联系人 UIView (5)查看.编辑 UI

实时监测input控件value值动态变化的事件

目录 [1]input [2]propertychange [3]兼容处理 前面的话 HTML5为input控件新增了很多type属性,大大增加了input控件的应用场景.其中一个是type="range"的input控件,可以通过拖动游标改变value值,但并不是所有浏览器都可以实时显示,除了IE10+浏览器 说到改变value值的事件,首先想到的便是change事件,但change事件的触发条件是失去焦点并且value值改变.而游标拖动并没有失去焦点.所以,change事件并不能达

我的Android进阶之旅------&gt;Android中ListView中嵌套(ListView)控件时item的点击事件不起作的问题解决方法

开发中常常需要自己定义Listview,去继承BaseAdapter,在adapter中按照需求进行编写,问题就出现了,可能会发生点击每一个item的时候没有反应,无法获取的焦点. 如果你的自定义ListViewItem中有Button.ImageButton或者Checkable的子类控件的话,那么默认focus是交给了子控件,而ListView的Item能被选中的基础是它能获取Focus.所以常常当点击item时变化的是子控件,item本身的点击没有响应. 这时候就可以使用descendan

我的Android进阶之旅------&amp;gt;Android中ListView中嵌套(ListView)控件时item的点击事件不起作的问题解决方法

开发中经常须要自定义Listview,去继承BaseAdapter,在adapter中依照需求进行编写,问题就出现了,可能会发生点击每个item的时候没有反应,无法获取的焦点. 假设你的自己定义ListViewItem中有Button.ImageButton或者Checkable的子类控件的话,那么默认focus是交给了子控件,而ListView的Item能被选中的基础是它能获取Focus. 所以经常当点击item时变化的是子控件,item本身的点击没有响应. 这时候就能够使用descendan