Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw border around a Control on Button_Click

When a user clicks my Validate Button (in my C#, WinForm, .net 3.5 app) I would like to draw a border around a certain control if it is empty. Say a textbox that is named tbxLastName I thought I needed to do something like this -->

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

Unfortunately, I have no idea what to put for the Graphics Object as what I have does NOTHING.

All of the examples I have come across, MSDN - HERE, have this code in a Paint Event. Like so -->

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

I, however, only want to have the border appear while certain conditions are meet which is kicked off by a Button_Click


So many of the suggestions suggest using a container object to hold the textbox and call it's Paint_Event. I did this and a box appears but NOT around the control. It appears in the Top Left corner of the Container Control. Here is what I am doing -->

    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

This is what I came up with combining suggestions here with what worked for 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);
                }
            }
        }
    }

I call this from the Paint_Event of any Container I need to.

like image 305
Refracted Paladin Avatar asked Feb 03 '10 16:02

Refracted Paladin


2 Answers

you can use a list of actions field in the form and add or remove, custom drawings:

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

This way you can add more than one border

like image 168
Alex LE Avatar answered Sep 28 '22 14:09

Alex LE


I just did something similar with VB.Net, with help from this thread. I have a Panel container around each set of my controls, and in the OnPaint handler for the Panel, I loop through all the children controls in the Panel and draw borders around them if they have the tag="required". I only display the borders on Edit or New so I created the fVisible parameter to toggle these on and off. When I want to fire this off, I call Panel.Refresh() so it fires the OnPaint event. This way all I have to do is set the tags on the required controls at design time, and add a handler for the container Panels, and it all works dynamically.

Here's the shared function I'm calling from all of my Panel's OnPaint Event Handlers. (Sorry I know you're using C# and this is VB but it's pretty basic.)

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
like image 38
Shawn Steward Avatar answered Sep 28 '22 16:09

Shawn Steward