2010-02-03 43 views
5

Cuando un usuario hace clic en mi botón Validar (en mi aplicación C#, WinForm, .net 3.5) Me gustaría dibujar un borde alrededor de un cierto control si está vacío. Decir un cuadro de texto que se nombra tbxLastName pensé que tenía que hacer algo como esto ->Dibujar borde alrededor de un Control en Button_Click

ControlPaint.DrawBorder(Graphics.FromHwnd(this.Handle), 
    tbxLastName.ClientRectangle, Color.Firebrick, ButtonBorderStyle.Solid); 

Por desgracia, no tengo idea de qué poner a los objetos gráficos como lo que tengo no hace nada.

Todos los ejemplos que he encontrado, MSDN - HERE, tienen este código en un evento de pintura. Al igual que ->

private void panel1_Paint(object sender, PaintEventArgs e) 
{  
    ControlPaint.DrawBorder(e.Graphics, this.panel1.ClientRectangle, 
     Color.DarkBlue, ButtonBorderStyle.Solid); 
} 

que, sin embargo, sólo quieren tener la frontera aparece mientras se reúnen ciertas condiciones son que se inició por una Button_Click


Así que muchas de las sugerencias sugerir el uso de una contenedor para mantener el cuadro de texto y llamarlo Paint_Event. Hice esto y aparece una caja pero NO alrededor del control. Aparece en la esquina superior izquierda del control de contenedores. Aquí es lo que estoy haciendo ->

private void grpImmunizationCntrl_Paint(object sender, PaintEventArgs e) 
    { 
     if (lkuNOImmunizationReason.Text.Equals(string.Empty) 
     { 
      ControlPaint.DrawBorder(
        e.Graphics, lkuNOImmunizationReason.ClientRectangle, 
         Color.Firebrick, ButtonBorderStyle.Solid); 
     } 
    } 

EDITAR

Esto es lo que ocurrió con la combinación de sugerencias aquí con lo que funcionó para mí.

public static void HighlightRequiredFields(Control container, Graphics graphics, Boolean isVisible) 
    { 
     Rectangle rect = default(Rectangle); 
     foreach (Control control in container.Controls) 
     { 
      if (control.Tag is string && control.Tag.ToString() == "required") 
      { 
       rect = control.Bounds; 
       rect.Inflate(3, 3); 
       if (isVisible && control.Text.Equals(string.Empty)) 
       { 
        ControlPaint.DrawBorder(graphics, rect, Color.FromArgb(173,216,230), ButtonBorderStyle.Solid); 
       } 
       else 
       { 
        ControlPaint.DrawBorder(graphics, rect, container.BackColor, ButtonBorderStyle.None); 
       } 
      } 

      if (control.HasChildren) 
      { 
       foreach (Control ctrl in control.Controls) 
       { 
        HighlightRequiredFields(ctrl, graphics, isVisible); 
       } 
      } 
     } 
    } 

Yo llamo a esto desde el Paint_Event de algunos recipientes que necesito.

+0

Gráficos es el equivalente de un Win32 DC. http://msdn.microsoft.com/en-us/library/dd162467(VS.85).aspx –

Respuesta

2

Acabo de hacer algo similar con VB.Net, con ayuda de este hilo.Tengo un contenedor Panel alrededor de cada conjunto de mis controles, y en el controlador OnPaint para el Panel, recorro todos los controles secundarios en el Panel y dibujo los bordes alrededor de ellos si tienen el tag="required". Solo muestro los bordes en Editar o Nuevo, así que creé el parámetro fVisible para alternar entre activar y desactivar. Cuando deseo desactivar esto, llamo al Panel.Refresh() para que se active el evento OnPaint. De esta forma, todo lo que tengo que hacer es establecer las etiquetas en los controles requeridos en el momento del diseño, y agregar un controlador para los paneles del contenedor, y todo funciona dinámicamente.

Aquí está la función compartida que estoy llamando desde todos los controladores de eventos OnPaint de mi Panel. (Lo siento, sé que estás usando C# y esto es VB, pero es bastante básico.)

Friend Sub HighlightRequiredFields(ByVal pnlContainer As Panel, ByVal gr As Graphics, ByVal fVisible As Boolean) 
    Dim rect As Rectangle 
    For Each oControl As Control In pnlContainer.Controls 
     If TypeOf oControl.Tag Is String AndAlso oControl.Tag.ToString = "required" Then 
      rect = oControl.Bounds 
      rect.Inflate(1, 1) 
      If fVisible Then 
       ControlPaint.DrawBorder(gr, rect, Color.Red, ButtonBorderStyle.Solid) 
      Else 
       ControlPaint.DrawBorder(gr, rect, pnlContainer.BackColor, ButtonBorderStyle.None) 
      End If 
     End If 
     If TypeOf oControl Is Panel Then HighlightRequiredFields(DirectCast(oControl, Panel), gr, fVisible) 
    Next 
End Sub 
+0

Una manera interesante de hacerlo, gracias. Creo que combinaré tu camino con lo que publiqué a continuación, ya que necesito lo más destacado para irme si se introduce el texto. Desafortunadamente, tenemos un modelo muy inusual en que no hagan clic en Editar o Nuevo primero, pero DESPUÉS de que hayan ingresado los datos. ¡Extraño, lo sé! –

+0

Jaja, eso definitivamente es werid. Me alegra ayudar. –

1

Los cuadros de texto no llaman al método OnPaint (consulte Note sección de this page). Una forma de evitar esto es colocar el cuadro de texto en un panel, que es un poco más grande. Luego, cambie el color de fondo cada vez que haga clic en el botón. Un hilo en MSDN forums tiene algunas soluciones.

Editar Para aclarar la solución de panel, basta con crear un panel y una su cuadro de texto a ella: por ejemplo,

private void MyForm_Load(object sender, EventArgs e) 
{ 
    myPanel.Controls.Add(tbxLastName); //Make sure the panel size is slightly bigger than the text box (so that it looks like a border) 
} 

Entonces, manejar su evento de clic de botón:

private void myButton_Click(object sender, EventArgs e) 
    { 
     if (tbxLastName.Text == "") 
     { 
      myPanel.BackColor = Color.Red; 
     } 
     else 
     { 
      myPanel.BackColor = Color.Transparent; 
     } 
    } 
+0

¿Qué tal si es un control que tiene un método OnPaint? Además, ¿alguna idea sobre por qué, cuando la coloqué en un cuadro de grupo, le faltaba el control cuando dibujaba el Rect (ver Editar en la parte inferior de OP)? Gracias –

+0

A menos que haya un motivo por el que quiera utilizar el método OnPaint, puede probar el método en mi respuesta actualizada. – keyboardP

+0

Oh, veo lo que estás haciendo ahora. Tendré que pensar en esto. Tengo entre 30 y 40 controles que PODRÍAN obtener una Caja dibujada a su alrededor. Me pregunto cómo implementaría esto en esa escala. –

3

se puede utilizar una lista de campo de las acciones en la forma y añadir o eliminar, dibujos personalizados:

// field 
List<Action<Graphics>> drawings = new List<Action<Graphics>>(); 

// on click event: 
drawings.Add(delegate(Graphics g) { 
    var rect = tbxLastName.Bounds; 
    rect.Inflate(1, 1); // make rectange a bit larger than textbox 
    ControlPaint.DrawBorder(g, rect, 
    Color.DarkBlue, ButtonBorderStyle.Solid); 
}); 
// make sure you added only once or clear before 
panel1.Refresh(); // refresh panel to force painting 


// Paint method: 
foreach (var draw in drawings) { 
    draw(e.Graphics); 
} 

esta manera puede agregar más de un borde

+1

+1 para señalar el método .Inflate, nunca me di cuenta de que ¡una vez, muy útil! –

1
protected override void OnTextChanged(EventArgs e) 
    { 
     base.OnTextChanged(e); 
     if (string.IsNullOrEmpty(Text)) 
     { 
      this.BorderStyle = BorderStyle.FixedSingle; 
     } 
     else 
     { 
      this.BorderStyle = BorderStyle.Fixed3D; 
     } 
    } 
1

El motivo de que su rectángulo "falta" en el cuadro de texto es que ClientRectangle solo contiene el tamaño del control, no la ubicación. Pruebe esto en su lugar:

private void grpImmunizationCntrl_Paint(object sender, PaintEventArgs e) 
{ 
    if (lkuNOImmunizationReason.Text.Equals(string.Empty) 
    { 
     ControlPaint.DrawBorder(
       e.Graphics, new Rectangle(lkuNOImmunizationReason.Left, lkuNOImmunizationReason.Top, lkuNOImmunizationReason.ClientRectangle.Width, lkuNOImmunizationReason.ClientRectangle.Height), 
        Color.Firebrick, ButtonBorderStyle.Solid); 
    } 
} 
Cuestiones relacionadas