2010-03-02 18 views
11

Estoy creando un control personalizado derivado de UserControl al que me gustaría enfocar.Configuración del foco en .NET UserControl ...?

El control personalizado contiene un control ComboBox y dibujo algunas cadenas junto a él.

El ComboBox puede recibir el foco, pero me gustaría poder enfocar el UserControl. Mi controlador OnPaint está configurado para dibujar el control de forma ligeramente diferente si tiene foco, pero yo llamo a CanFocus() desde el formulario principal cuando creo mi control personalizado y devuelve falso.

¿Hay alguna propiedad o algo para configurar?

Respuesta

21

UserControl luchará con uñas y dientes para evitar enfocarse. Tiene un código que automáticamente pasa el foco a un control secundario (si existe) si obtiene el foco. Como mínimo deberá anular WndProc() y atrapar el mensaje WM_SETFOCUS. Es posible que se necesite otra cirugía, como ControlStyles.Selectable y las propiedades TabStop y TabIndex.

Su próximo problema es que UserControl no responderá significativamente, por ejemplo, a los mensajes del teclado cuando tiene foco. Necesitará detectar clics en el fondo de UC para manejar los mensajes del mouse, así como anular la pintura, por lo que es obvio para el usuario que la UC tiene el foco (use ControlPaint.DrawFocusRectangle). Si esto empieza a sonar poco atractivo, es porque UC realmente pretendía ser un control de contenedor.

+1

Esto pareció hacer el trabajo. Continuaré jugando con él para resolver las complejidades que mencionaste. ¡Gracias! – Sambo

+1

+1 Me alegra tener otra gran respuesta de NoBugz. Curioso: en este caso, ¿cree que el OP podría ser mejor utilizando un Formulario en lugar de un UserControl? – BillW

+2

@Bill: la clase Form también es un control de contenedor, aunque no se defenderá de la misma manera. Mi consejo debería ser evitar las prácticas de IU no estándar. Confunde al usuario también. –

1

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

Observaciones

Para que un control para recibir foco de entrada, el control debe tener un mango asignado a él, y lo visible y propiedades Enabled debe tanto ser establecido en true para el control y todos sus controles principales, y el control debe ser un formulario cont el padre externo de rol debe ser un formulario .

Asegúrese de cumplir estas prerrequisitos.

+1

Gracias por su respuesta ... He confirmado que mi control tiene un valor para Handle. El control es visible y también está habilitado, y el panel en el que lo visualizo es visible y habilitado también ... ¡y todo aparece en un formulario ...! Parece que cumple con los requisitos previos ... Anula OnGotFocus() y establezco un punto de interrupción pero nunca se golpeó. Además, configuré un controlador en mi objeto de formulario para el evento GotFocus del control y, una vez más, el código nunca fue golpeado. ¿Alguna otra idea ...? – Sambo

+0

Estos requisitos previos se aplican a Control, pero UserControl sabotea esto como @HansPassant mencionado anteriormente. –

1

demasiado largo para un comentario, incluye enlace, y el código ... pero esto es un comentario ...

Muchas personas se han quejado de un control de usuario que no se dispare el evento GotFocus(). Por ejemplo: UserControl and GotFocus() fyi: LostFocus() se activará como se esperaba, en mi experiencia. En el pasado, en un proyecto de Formularios múltiples, he experimentado con la implementación de 'Ingresar' y 'Dejar manejadores de eventos en un UserControl en cada Formulario, y descubrí que' Intro solo se invoca en Carga de formulario, una vez.

Evidentemente, los controles en el UserControl "tomar foco" (de una manera que no puedo explicar, pero tal vez uno de los gurús de WinForms de SO lo hará). ¿Quizás esto se relaciona con el hecho de que UserControl desciende de ContainerControl?

que experimentaron con la escritura una 'GotFocus() manejador:

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

Y luego, en el control de usuario' evento de carga, cable de seguridad de todos los controles en el control de usuario a ese controlador de eventos: lo que observé fue que el Control en el UserControl con el TabIndex más bajo activará el evento 'GotFocus' tan solo al iniciar la aplicación y al cambiar de Formularios.

La única otra cosa que he mencionado en esta situación es asegurarse de que la propiedad 'IsTabStop del UserControl está configurada en' Verdadero: esto era de Shawn Wildermuth en MS en el contexto de una pregunta relacionada con SilverLight, entonces no tengo idea de si esto podría aplicarse en tu caso.

Otra sugerencia, que era escribir un controlador de eventos MouseDown o MouseClick para el UserControl, y en esa llamada: this.SetFocus(); no me llevó a ninguna parte.

Espero que tengas una respuesta!

1

En algunos casos, también es deseable no permitir que el foco se mueva a los elementos secundarios de un UserControl.
En este caso, también necesita establecer ControlStyles.ContainerControl en falso.

Public Sub New() 
    InitializeComponent() 

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

End Sub 
0

Diga, usted tiene una imagen en el control de usuario y desea poner de relieve que imita el evento "GetFocus" (por ejemplo centrarse en el control de usuario toma la foto). El enfoque en su control de usuario se manejará dibujando una línea discontinua en el PictureBox. Esto se hace a través de sus eventos OnEnter y OnLeave de control de usuario. Aquí está el procedimiento resaltado ...

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 

Estas dos anulaciones harán el trabajo.

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

Si UserControl obtiene el foco, internamente pasa el foco a su control secundario.

Por lo tanto, deberá omitir la ejecución del código que establece el foco en el control secundario. Para eso, tendrá que anular la ejecución omitida de WndProc() de cualquier mensaje 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); 
    } 
} 

Donde WM_SETFOCUS es "0x0007".

Cuestiones relacionadas