2010-03-02 111 views
11

我正在創建一個從UserControl派生的自定義控件,我想將焦點設置爲。將焦點設置爲.NET UserControl ...?

自定義控件包含一個ComboBox控件,並在其旁邊繪製一些字符串。

ComboBox可以接收焦點,但我希望能夠將焦點設置到UserControl本身。我的OnPaint處理程序設置爲稍微不同地繪製該控件,如果它具有焦點但我創建自定義控件時返回false從父窗體調用CanFocus()。

是否有屬性或設置?

回答

21

UserControl會打你的牙齒和指甲,以避免獲得焦點。它有自動將焦點傳遞給子控件(如果有的話)的代碼,如果它確實得到焦點。您至少必須重寫WndProc()並捕獲WM_SETFOCUS消息。可能需要其他手術,如ControlStyles.Selectable和TabStop和TabIndex屬性。

您的下一個問題是UserControl在確實有焦點時不會對鍵盤消息做出有意義的響應。您需要檢測UC背景上的點擊以處理鼠標消息,以及覆蓋該繪畫,以便用戶明白UC具有焦點(使用ControlPaint.DrawFocusRectangle)。如果這聽起來沒有吸引力,那是因爲UC真的是一個容器控制。

+1

這似乎是做這項工作。我會繼續玩弄它來解決你提到的錯綜複雜的問題。謝謝! – Sambo 2010-03-02 12:48:19

+1

+1很高興能有NoBugz的另一個偉大的答案。好奇:在這種情況下,你認爲OP使用Form而不是UserControl可以做得更好嗎? – BillW 2010-03-02 14:20:26

+2

@Bill:Form類也是一個容器控件,雖然它不會以相同的方式反擊。我的建議必須是避免非標準的UI練習。它也使用戶感到困惑。 – 2010-03-02 15:49:10

1

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.canfocus.aspx

備註

爲了控制以接收 輸入焦點時,控制必須具有 手柄分配給它,並且可見 和Enabled屬性必須既對於控制和 所有其父控件以及 控件都必須爲表格或 cont rol的最外層父項必須是 表單。

確保您符合這些prerequesits。

+1

感謝您的回覆... 我已確認我的控件具有Handle值。該控件是可見和啓用,我也顯示它的面板是可見和啓用以及...它都出現在窗體上...! 這似乎符合先決條件... 我覆蓋OnGotFocus()並設置一個斷點,但它從來沒有被擊中。另外,我在控件的GotFocus事件的窗體對象中設置了一個處理程序,並且再次,代碼從未被擊中。 任何其他想法...? – Sambo 2010-03-02 11:42:48

+0

這些先決條件適用於Control,但UserControl將其作爲上述@HansPassant進行破壞。 – 2014-09-23 17:01:40

1

太長了評論,包括鏈接和代碼...但是這是一條評論...

很多人都抱怨沒有發射了「的GotFocus()事件用戶控件。例如:UserControl and GotFocus() fyi:按照我的經驗,LostFocus()會按預期發射。在過去,在一個多表單項目中,我嘗試在每個表單的UserControl上實現「輸入和」事件處理程序,並發現「輸入只在表單加載時調用一次。

很明顯,UserControl上的控件「聚焦」(我無法解釋,但也許是SO的WinForms大師之一)。也許這與UserControl從ContainerControl降落的事實有關?

我寫一個實驗「的GotFocus()處理:

private void Control_GotFocus(object sender, EventArgs e) 
    { 
     Console.WriteLine("Control GotFocus : " + ((sender as Control).Name)); 
    } 

,然後在用戶控件」 Load事件,在用戶控件到事件處理程序連接好所有的控件:我觀察到的是, UserControl上的最低TabIndex控件會在啓動應用程序時觸發'GotFocus事件,並在Forms之間切換。

我在這種情況下提到的唯一的其他事情是確保UserControl的IsTabStop屬性設置爲True:這是在SilverLight相關問題的上下文中來自Shawn Wildermuth的,所以不知道這是否適用於你的情況。

另一個建議是爲UserControl編寫一個MouseDown或MouseClick事件處理程序,並在該調用中:​​使我無處可去。

希望你得到答案!

1

在某些情況下,也不希望焦點移動到UserControl的子元素。
在這種情況下,您還需要將ControlStyles.ContainerControl設置爲false。

Public Sub New() 
    InitializeComponent() 

    Me.SetStyle(ControlStyles.ContainerControl, False) 
    Me.SetStyle(ControlStyles.Selectable, True) 

End Sub 
0

說,你有你的用戶控件的圖片,你想突出它模仿「GetFocus」事件(比如專注於你的用戶控件藉此圖片)。對用戶控件的關注將通過向圖片框繪製輪廓虛線來處理。這是通過您的用戶控件OnEnter和OnLeave事件完成的。這是高亮程序...

Public Sub highlightImage() 
    Dim l As Single() = {2, 2, 2, 2} 
    Dim p As New Pen(Color.Gray, 1) 
    p.DashPattern = l 
    Dim g As Graphics = picColor.CreateGraphics() 
    g.DrawRectangle(p, 0, 0, picColor.Width - 1, picColor.Height - 1) 
End Sub 

這兩個覆蓋將完成這項工作。

Protected Overrides Sub OnEnter(e As EventArgs) 
    MyBase.OnEnter(e) 
    Me.highlightImage() 
End Sub 
Protected Overrides Sub OnLeave(e As EventArgs) 
    MyBase.OnLeave(e) 
    MyBase.Refresh() 
End Sub 
0

如果UserControl獲得焦點,它會在內部將焦點傳遞給其子控件。

因此,您需要跳過執行將焦點設置爲子控件的代碼。爲此,您需要重寫WndProc()跳過任何WM_SETFOCUS消息的執行。

public class FocusableUserControl : UserControl 
{ 
    protected override void WndProc(ref Message m) 
    { 
     switch (m.Msg) 
     { 
      case (int)Win32Constants.WM_SETFOCUS: 
      //Returning from here will skip setting focus to child controls. 
      //It will not skip setting focus to this control. 

       Console.WriteLine("FocusableUserControl is focused: " + Focused); 
       return; 
     } 

     base.WndProc(ref m); 
    } 
} 

其中WM_SETFOCUS是「0x0007」。