程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#中如何讓工具欄ToolStrip能觸發焦點控件

C#中如何讓工具欄ToolStrip能觸發焦點控件

編輯:關於C#

C#中如何讓工具欄ToolStrip能觸發焦點控件的Leave、Validating、DataError等事件以驗證數據

如題,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
// http://www.bianceng.cn/Programming/csharp/201410/45478.htm
    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消息還是玩不轉~總之是經歷過若干次失敗的嘗試,我不得不放棄高大上的解決辦法,這才回頭來重新拾起猥瑣方案,所以文中辦法其實是妥協的結果,難免心有不甘,等他日機緣到了,我定再次嘗試“正統”的解決辦法。如有路過高人點撥,感激不盡!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved