2010-03-27 11 views
9

Estoy implementando un control personalizado que hereda de Control. Quiero que sea enfocable (es una especie de cuadro de lista).¿Realmente tengo que llamar a Focus en OnMouseDown de mi control personalizado?

En el constructor, que hago

SetStyle(ControlStyles.Selectable, true); 

ahora puedo usar Tab para desplazarse al control.

Sin embargo, cuando el control recibe un clic del mouse, no reclama automáticamente el foco. Puedo solucionar este problema, por supuesto:

protected override void OnMouseDown(MouseEventArgs e) 
{ 
    Focus(); 
    base.OnMouseDown(e); 
} 

Pero esto se siente como una chapuza que no debería ser necesario. ¿Es este realmente el camino a seguir? ¿O hay alguna forma de decirle al Control que reclame el enfoque automáticamente cuando recibe un clic del mouse?

+0

@Thomas: mencionas "Ya tenía el rectángulo de foco en su lugar": ¿estás haciendo esto sobrepasando OnGotFocus, y OnLostFocus y llamando a ControlPaint.DrawFocusRectangle? Apreciar cualquier respuesta. – BillW

+1

@BillW: Sí, eso es lo que hago. 'OnGotFocus' y' OnLostFocus' invalidan el rectángulo que contiene el rectángulo de foco; 'OnPaint' comprueba la propiedad' Focused' y llama 'ControlPaint.DrawFocusRectangle' según sea necesario. – Thomas

+0

sus respuestas de los pacientes a mis preguntas muy apreciadas! Estoy publicando una respuesta más que es la única forma en que puedo hacer que esto funcione en Visual Studio RC1 compilado contra FrameWork 3.5 (completo). Por "trabajo": me refiero a que cuando el control está "tabtado a:" se muestra un rectángulo de selección, y cuando "tabbed-away-from" el rectángulo de selección desaparece: y cuando se presiona el control se muestra el rectángulo de selección. – BillW

Respuesta

4

¡Desmontaje al rescate! Resulta que

SetStyle(ControlStyles.UserMouse, true); 

hace el truco.

Irónicamente, había leído en el documentation:

UserMouse: Si es verdad, el control hace su propio procesamiento de ratón, y eventos de ratón no son manejados por el sistema operativo.

que parecía exactamente lo contrario de lo que quería, así que sólo había intentado fijar a false ... Así se hace, la documentación de Windows Forms.

+2

Esto no es correcto. Desactivar el estilo de UserMouse solo debe hacerse para envoltorios de clase de control alrededor de controles nativos que implementan su propio procesamiento de mensaje de mouse. Permite que un control tome el foco porque le interesan los eventos de entrada. Intencionalmente desactivar el procesamiento de eventos de entrada no tiene sentido. –

+0

La frase "el control hace su propio procesamiento de mouse" es muy confusa a la luz de su aclaración: ¿el control * WinForms * hace su propio procesamiento de mouse (sobreescribiendo 'OnMouseDown' etc.) o el control * native * hace su propio procesamiento del mouse (lo que significa que el control WinForms debe mantenerse alejado de él)? De todos modos, aparentemente 'UserMouse' era' falso' por defecto. Y dado que no estoy envolviendo un control nativo, debería ser 'verdadero', ¿verdad? – Thomas

+0

Sí lo hace, llama al método OnMouseDown. Que anularías para darle tu propio control al comportamiento del mouse. Como darle el enfoque. Su control hereda de Control, no hay un control nativo de Windows envuelto (como ListBox o TreeView). Es solo una ventana simple. –

2

Sí, eso es lo que debes hacer. Hay muchos controles que no tienen una forma significativa de tomar el foco. PictureBox, Panel son buenos ejemplos. Cualquier cosa que se derive de ContainerControl. Control.OnMouseDown() por lo tanto no llama automáticamente a Focus() en OnMouseDown().

Simplemente anulando el método OnMouseDown no es suficiente, también debe dejar en claro para el usuario que su control tiene el foco. Entonces ella tendrá una idea de dónde van los trazos del teclado. Eso requiere anular OnPaint() para que pueda dibujar un rectángulo de enfoque. ControlPaint.DrawFocusRectangle() es una implementación estándar para eso.

Pero enfocarse realmente solo es útil si hace algo significativo con los mensajes del teclado. Por lo tanto, deberá anular OnKeyDown y/o OnKeyPressed también. Y muestre sus comentarios al usuario para que pueda ver lo que escribió. Si no tiene una implementación útil para eso, no debe enfocarse. Por eso PictureBox no.

+0

Buenos puntos, pero ¿por qué crees que quería que el control sea enfocable en primer lugar? Ya tenía el rectángulo de foco en su lugar, y ahora estoy trabajando en los manejadores de teclado. – Thomas

+3

Siempre es bueno mencionar este tipo de detalles en la pregunta. –

+0

Mencioné entre paréntesis que es un tipo de cuadro de lista, que en cierto modo implicaba que debería manejar las pulsaciones de teclas; No quería distraerme del problema mencionando todos estos detalles. Pero tiene razón: es bueno dar información sobre la parte "¿por qué querría eso?", Porque a veces resulta que realmente quiere resolver o eludir el problema subyacente de una manera completamente diferente. – Thomas

0
  1. de compilación en un proyecto de Windows Forms Framework 3.5 para

  2. arrastre una instancia de Control1 desde el cuadro de herramientas para una superficie de la forma ... asegurarse de su propiedad PuntoDeTabulación se establece en 'verdadero

  3. ponga algunos otros controles en el formulario.

  4. compruebe que cuando la instancia de Control1 está en pestañas: muestra un rectángulo de selección que desaparece a medida que "tab" lejos de él.

  5. compruebe si hace clic en la instancia de Control1 que muestra el rectángulo de selección, y si hace clic en algún otro control, desaparece.

    namespace testFocusableControl 
    { 
        // VS Studio 2010 RC1 : Tested against FrameWork 3.5 Full (not 'Client) 
    
        public class Control1 : Control 
        { 
         public Control1() 
         { 
          SetStyle(ControlStyles.UserMouse, true); 
         } 
    
         protected override void OnLostFocus(EventArgs e) 
         { 
          this.Invalidate(); 
          base.OnLostFocus(e); 
         } 
    
         protected override void OnGotFocus(EventArgs e) 
         { 
          this.Invalidate(); 
          base.OnGotFocus(e); 
         } 
    
         protected override void OnPaint(PaintEventArgs e) 
         { 
          if (this.Focused) 
          { 
           ControlPaint.DrawFocusRectangle(e.Graphics, this.ClientRectangle, Color.Red, Color.Blue); 
          } 
          base.OnPaint(e); 
         } 
        } 
    } 
    

La única "cabo suelto" aquí para mí es que esta solución se mostrará el rectángulo de selección en un clic del ratón, pero no aplicar ningún código MouseDown como sugiere Thomas.

Tenga en cuenta que si realiza el control sobre un 'ContainerControl a través de' SetStyle (ControlStyles.ContainerControl, true); y agregue algún otro control, incluso si establece la propiedad TabStop del control agregado en 'falso: ... si hizo clic ... obtendrá foco, y perderá el rectángulo de enfoque que se muestra en ContainerControl.

+1

Los métodos que marcó como '// no effect' no funcionan porque los declaró' virtuales', no 'override'. Aparentemente 'UserPaint' y' Selectable' están por defecto en 'true'. En cuanto al # 6: no entender su código siempre es malo, independientemente de si funciona. Pero creo que ahora entendemos qué funciona y qué no funciona * y * por qué, ¿no? :) – Thomas

+0

+1 Muchas gracias, Thomas por sus ideas. He revisado el código para incorporar su información. ! – BillW

Cuestiones relacionadas