zoukankan      html  css  js  c++  java
  • 工具栏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消息还是玩不转~总之是经历过若干次失败的尝试,我不得不放弃高大上的解决办法,这才回头来重新拾起猥琐方案,所以文中办法其实是妥协的结果,难免心有不甘,等他日机缘到了,我定再次尝试“正统”的解决办法。

  • 相关阅读:
    HDU 1863 畅通工程(Kruskal)
    HDU 1879 继续畅通工程(Kruskra)
    HDU 1102 Constructing Roads(Kruskal)
    POJ 3150 Cellular Automaton(矩阵快速幂)
    POJ 3070 Fibonacci(矩阵快速幂)
    ZOJ 1648 Circuit Board(计算几何)
    ZOJ 3498 Javabeans
    ZOJ 3490 String Successor(模拟)
    Java实现 LeetCode 749 隔离病毒(DFS嵌套)
    Java实现 LeetCode 749 隔离病毒(DFS嵌套)
  • 原文地址:https://www.cnblogs.com/zeroone/p/4107005.html
Copyright © 2011-2022 走看看