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,23开发者_如何学运维0), 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.
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
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
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
if (string.IsNullOrEmpty(Text))
{
this.BorderStyle = BorderStyle.FixedSingle;
}
else
{
this.BorderStyle = BorderStyle.Fixed3D;
}
}
The reason that your rectangle is "missing" the text box is that ClientRectangle only contains the size of the control, not the location. Try this instead:
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);
}
}
Textboxes do not call the OnPaint method (See Note
section of this page
). A way round this, is to place the textbox in a panel, which is slightly bigger. Then, change the background colour whenever the button is clicked. A thread over at MSDN forums has a few solutions.
Edit To clarify the panel solution, simply create a panel and add your textbox to it: e.g.
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)
}
Then, handle your button click event:
private void myButton_Click(object sender, EventArgs e)
{
if (tbxLastName.Text == "")
{
myPanel.BackColor = Color.Red;
}
else
{
myPanel.BackColor = Color.Transparent;
}
}
精彩评论