2010-02-03 3 views
5

Quando un utente fa clic sul mio pulsante di convalida (nel mio C#, WinForm, .net 3.5 app) Vorrei disegnare un bordo attorno a un determinato controllo se è vuoto. Dire una casella di testo che è denominato tbxLastName ho pensato che avevo bisogno di fare qualcosa di simile ->Disegna il bordo attorno a un controllo Button_Click

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

Purtroppo, non ho idea di cosa mettere per l'oggetto Graphics come quello che ho non fa nulla.

Tutti gli esempi che ho trovato, MSDN - HERE, hanno questo codice in un evento Paint. In questo modo ->

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

Io, invece, vogliono solo avere il bordo viene visualizzato durante certe condizioni si incontrano, che è ha dato il via da un Button_Click


Così molti dei suggerimenti suggeriamo di utilizzare un oggetto contenitore per contenere la casella di testo e chiamarla Paint_Event. Ho fatto questo e appare una scatola ma NON intorno al controllo. Appare nell'angolo in alto a sinistra del Controllo contenitore. Ecco quello che sto facendo ->

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

EDIT

Questo è ciò che mi si avvicinò con la combinazione suggerimenti qui con ciò che ha funzionato per me.

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

Io chiamo questo dal Paint_Event di qualsiasi contenitore ne ho bisogno.

+0

La grafica è l'equivalente di un DC Win32. http://msdn.microsoft.com/en-us/library/dd162467(VS.85).aspx –

risposta

2

Ho appena fatto qualcosa di simile con VB.Net, con l'aiuto di questo thread.Dispongo di un contenitore Panel attorno a ciascun set dei miei controlli e nel gestore OnPaint per lo Panel, eseguo il ciclo di tutti i controlli secondari nello Panel e disegna bordi attorno a loro se dispongono dello tag="required". Visualizzo solo i bordi su Modifica o Nuovo, quindi ho creato il parametro fVisible per attivarli e disattivarli. Quando desidero attivarlo, chiamo lo Panel.Refresh() in modo che venga attivato l'evento OnPaint. In questo modo tutto ciò che devo fare è impostare i tag sui controlli richiesti in fase di progettazione e aggiungere un gestore per i pannelli Contenitore, e tutto funziona in modo dinamico.

Ecco la funzione condivisa che sto chiamando da tutti i gestori di eventi OnPaint del mio pannello. (Mi spiace, so che stai usando C# e questo è VB ma è piuttosto semplice.)

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

Un modo interessante per farlo, grazie. Penso che combinerò il tuo modo con quello che ho postato qui sotto, perché ho bisogno che l'evidenziazione scompaia se il testo è inserito. Sfortunatamente, abbiamo un modello insolito in che non fanno clic su Modifica o Nuovo, ma DOPO aver inserito i dati. Strano, lo so! –

+0

Haha che è sicuramente werid! Felice di aiutare. –

1

Le caselle di testo non chiamano il metodo OnPaint (Vedere la sezione Note di this page). Un modo per aggirare questo, è quello di posizionare la casella di testo in un pannello, che è leggermente più grande. Quindi, cambia il colore di sfondo ogni volta che si fa clic sul pulsante. Un thread su MSDN forums ha alcune soluzioni.

Modifica Per chiarire la soluzione di pannello, è sufficiente creare un pannello e aggiungere il vostro testo ad esso: per esempio

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

Poi, gestire il vostro evento click del pulsante:

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

Che ne dici se si tratta di un controllo con un metodo OnPaint? Inoltre, qualche idea sul perché, quando l'ho inserito in una groupbox, mancava il controllo quando ha disegnato il Rect (vedi Modifica in fondo all'OP)? Grazie –

+0

A meno che non vi sia un motivo per cui si desidera utilizzare il metodo OnPaint, è possibile provare il metodo nella mia risposta aggiornata. – keyboardP

+0

Oh, capisco cosa stai facendo ora. Dovrò pensare a questo. Ho tra i 30 ei 40 controlli che POTREBBERO avere una scatola disegnata attorno a loro. Mi chiedo come implementarlo su questa scala. –

3

è possibile utilizzare un elenco di campo azioni in forma e aggiungere o rimuovere, disegni personalizzati:

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

In questo modo è possibile aggiungere più di un bordo

+1

+1 per indicare il metodo .Inflate, non l'ho mai notato uno prima, molto utile! –

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

La ragione per cui il rettangolo "manca" nella casella di testo è che ClientRectangle contiene solo la dimensione del controllo, non la posizione. Prova questo:

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