2010-03-02 25 views
11

Tôi đang tạo một điều khiển tùy chỉnh bắt nguồn từ UserControl mà tôi muốn đặt tiêu điểm.Đặt tiêu điểm thành một người dùng .NETControl ...?

Điều khiển tùy chỉnh chứa một điều khiển ComboBox và tôi vẽ một số chuỗi bên cạnh nó.

ComboBox có thể nhận tiêu điểm, nhưng tôi muốn có thể đặt tiêu điểm cho chính UserControl. Trình xử lý OnPaint của tôi được thiết lập để vẽ điều khiển hơi khác nếu nó có tiêu điểm nhưng tôi gọi CanFocus() từ biểu mẫu gốc khi tôi tạo điều khiển tùy chỉnh và trả về false.

Có tài sản hoặc thứ gì đó cần thiết không?

Trả lời

21

UserControl sẽ chống lại răng và móng tay của bạn để tránh bị lấy nét. Nó có mã tự động chuyển tiêu điểm vào điều khiển con (nếu có) nếu nó lấy tiêu điểm. Bạn sẽ ở mức tối thiểu phải ghi đè WndProc() và bẫy thông điệp WM_SETFOCUS. Có thể cần phẫu thuật khác, như các thuộc tính ControlStyles.Selectable và TabStop và TabIndex.

Vấn đề tiếp theo của bạn là UserControl sẽ không trả lời có ý nghĩa, ví dụ như tin nhắn bàn phím khi nó có tiêu điểm. Bạn sẽ cần phải phát hiện các nhấp chuột trên nền UC để xử lý các tin nhắn chuột, cũng như ghi đè lên bức tranh để hiển thị cho người dùng rằng UC có tiêu điểm (sử dụng ControlPaint.DrawFocusRectangle). Nếu điều này nghe có vẻ không hấp dẫn, đó là bởi vì UC thực sự có ý nghĩa như một điều khiển container.

+1

Điều này dường như thực hiện công việc. Tôi sẽ tiếp tục chơi xung quanh với nó để phân loại ra những phức tạp mà bạn đã đề cập. Cảm ơn! – Sambo

+1

+1 Vui mừng khi có một câu trả lời tuyệt vời khác từ NoBugz. Tò mò: trong trường hợp này bạn có nghĩ rằng OP có thể làm tốt hơn bằng cách sử dụng Biểu mẫu thay vì UserControl không? – BillW

+2

@Bill: Lớp Form cũng là một điều khiển container, mặc dù nó sẽ không chiến đấu theo cùng một cách. Lời khuyên của tôi sẽ phải tránh thực hành UI không chuẩn. Nó cũng gây nhầm lẫn cho người dùng. –

1

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

chú

Để cho một điều khiển để nhận tập trung đầu vào, kiểm soát phải có một tay cầm gán cho nó, và Visible và tài sản Enabled phải cả được đặt thành true cho cả điều khiển và tất cả các điều khiển gốc của nó và điều khiển phải là biểu mẫu hoặc tiếp cha mẹ ngoài cùng của rol phải là một hình thức .

Đảm bảo bạn đã đáp ứng các điều kiện tiên quyết này.

+1

Cảm ơn bạn đã trả lời ... Tôi đã xác nhận rằng kiểm soát của tôi có giá trị cho Xử lý. Control cũng có thể nhìn thấy và được kích hoạt và Panel tôi hiển thị nó bên trong là có thể nhìn thấy và được kích hoạt ... và tất cả xuất hiện trên một Form ...! Điều đó dường như đáp ứng các điều kiện tiên quyết ... Tôi đã khắc phục OnGotFocus() và đặt điểm ngắt nhưng không bao giờ bị trúng. Ngoài ra, tôi thiết lập một trình xử lý trong đối tượng biểu mẫu của tôi cho sự kiện GotFocus của điều khiển và, một lần nữa, mã không bao giờ bị tấn công. Bất kỳ ý tưởng nào khác ...? – Sambo

+0

Những điều kiện tiên quyết này áp dụng cho Kiểm soát, nhưng UserControl phá hoại điều này là @HansPassant được đề cập ở trên. –

1

quá dài cho một bình luận, bao gồm liên kết, và mã ... nhưng đây là một nhận xét ...

Rất nhiều người đã phàn nàn về một usercontrol không bắn các GotFocus() sự kiện'. Ví dụ: UserControl and GotFocus() fyi: LostFocus() sẽ kích hoạt như mong đợi, theo kinh nghiệm của tôi. Trong quá khứ, trong một dự án nhiều Biểu mẫu, tôi đã thử nghiệm với việc thực hiện 'Nhập và' Để xử lý sự kiện trên UserControl trên mỗi Biểu mẫu và thấy rằng 'Enter chỉ được gọi trên Tải biểu mẫu một lần.

Hiển nhiên các điều khiển trên UserControl "tập trung" (theo cách tôi không thể giải thích, nhưng có lẽ một trong những người dùng WinForms của SO sẽ). Có lẽ điều này liên quan đến thực tế là UserControl xuống từ ContainerControl?

tôi đã thử nghiệm với văn bản một 'GotFocus() xử lý:

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

Và sau đó, trong UserControl' sự kiện Load, dây lên tất cả các điều khiển trên UserControl để mà xử lý sự kiện: những gì tôi quan sát được là Kiểm soát trên UserControl với TabIndex thấp nhất sẽ kích hoạt sự kiện GotFocus ngay khi khởi chạy ứng dụng và khi chuyển đổi giữa các Biểu mẫu.

Điều duy nhất tôi đã thấy trong trường hợp này là đảm bảo 'thuộc tính IsTabStop của UserControl được đặt thành' Đúng: đây là từ Shawn Wildermuth tại MS trong ngữ cảnh của câu hỏi liên quan đến SilverLight, vì vậy không có ý tưởng nếu điều này có thể áp dụng trong trường hợp của bạn.

Một đề xuất khác, đó là viết trình xử lý sự kiện MouseDown hoặc MouseClick cho UserControl và trong cuộc gọi đó: this.SetFocus(); dẫn tôi đến hư không.

Hy vọng bạn nhận được câu trả lời!

1

Trong một số trường hợp, bạn cũng không muốn tập trung di chuyển đến các phần tử con của UserControl.
Trong trường hợp này, bạn cũng cần đặt ControlStyles.ContainerControl thành false.

Public Sub New() 
    InitializeComponent() 

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

End Sub 
0

Giả sử bạn có ảnh trên điều khiển người dùng và muốn đánh dấu nó bắt chước sự kiện "GetFocus" (hãy tập trung vào điều khiển người dùng của bạn chụp ảnh này). Việc tập trung vào kiểm soát người dùng của bạn sẽ được xử lý bằng cách vẽ một đường viền phác thảo đến PictureBox. Điều này được thực hiện thông qua sự kiện OnEnter và OnLeave của người dùng. Đây là quy trình đánh dấu ...

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 

Hai phần ghi đè này sẽ thực hiện công việc.

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

Nếu UserControl tập trung, nó sẽ chuyển tiêu điểm vào điều khiển con của nó.

Vì vậy, bạn sẽ cần bỏ qua việc thực thi mã đặt tiêu điểm cho kiểm soát trẻ em. Cho rằng bạn sẽ cần phải ghi đè lên WndProc() bỏ qua việc thực hiện bất kỳ thông báo WM_SETFOCUS nào.

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); 
    } 
} 

Nơi WM_SETFOCUS là "0x0007".

Các vấn đề liên quan