Drawing Rectangle as TextBox Border - c#

I'm using validation methods for my textboxes in a class named Validators. I'm trying also to draw a rectangle on the textbox which failed to validate.
Im using this code:
private void TextBoxStyle(TextBox textBox)
{
Graphics graphics = textBox.CreateGraphics();
Pen redPen = new Pen(Color.Red);
graphics.DrawRectangle(redPen, textBox.Location.X, textBox.Location.Y, textBox.Width, textBox.Height);
}
/// <summary>
/// Validates TextBoxes for string input.
/// </summary>
public bool ValidateTextBoxes(params TextBox[] textBoxes)
{
foreach (var textBox in textBoxes)
{
if (textBox.Text.Equals(""))
{
Graphics graphics = textBox.CreateGraphics();
Pen redPen = new Pen(Color.Red);
graphics.DrawRectangle(redPen, textBox.Location.X, textBox.Location.Y, textBox.Width, textBox.Height);
return false;
}
}
return true;
}
The problem is... the rectangles wont show. Am I doing something wrong with the code ? If yes, help please.

A couple potential problems I see:
You get the Graphics object for the text box but use the textbox's offset in the form to do the drawing. Net result: the rectangle is translated outside the visible area of the textbox. Try using the location (0,0).
You draw the rectangle as wide as the textbox. Net result: right and bottom edges won't be visible. You should subtract the width of the pen from these values.
While you're at it, check out the ErrorProvider class. It may just take care of your needs off-the-shelf.

write a user control
public partial class UserControl1 : UserControl
{
private string text;
private bool isvalid = true;
public string Text
{
get { return textBox.Text; }
set { textBox.Text = value; }
}
public bool isValid
{
set
{
isvalid = value;
this.Refresh();
}
}
TextBox textBox = new TextBox();
public UserControl1()
{
InitializeComponent();
this.Paint += new PaintEventHandler(UserControl1_Paint);
this.Resize += new EventHandler(UserControl1_Resize);
textBox.Multiline = true;
textBox.BorderStyle = BorderStyle.None;
this.Controls.Add(textBox);
}
private void UserControl1_Resize(object sender, EventArgs e)
{
textBox.Size = new Size(this.Width - 3, this.Height - 2);
textBox.Location = new Point(2, 1);
}
private void UserControl1_Paint(object sender, PaintEventArgs e)
{
if (isvalid)
ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle, Color.Black, ButtonBorderStyle.Solid);
else
ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle, Color.Red, ButtonBorderStyle.Solid);
}
}
update:
just added the isvalid property
you can put properties to show the border or not. if the input is valid show normal border and if the control input is invalid show the red border.

Anything drawn directly onto the TextBox will disappear as soon as the TextBox control is invalidated in some way.
A correct approach is to add a User Control to your project and add a TextBox on its canvas. Leave a little border around it.
You can now simply color the background of the user control's canvas red when needed and it will look like a border drawn around the TextBox.
You can add code directly to the user control to validate it whenever the text changes. That way, you only have to write code once and just add as many TextBoxes as you need to your forms or pages.

You shouldn't paint on a control simply from somewhere. The build in painting will override it on the next occasion. The Control has a paint event where you should paint. That will be used whenever painting is needed.
In your validate method you should just store the result of the validation somewhere so that it can be used in the paint event and call Invalidate() so that a repainting is enforced.

// You may use this
Label lblHighlight = new Label ();
Rectangle rc = new Rectangle(this.Left - 2, this.Top - 2, this.Width + 4, this.Bottom - this.Top + 4);
this.Parent.Controls.Add(lblHighlight);
lblHighlight.Bounds = rc;
lblHighlight.BackColor = "Red";

Related

Password char doesnt work when i try to make my custom TextBox

I made a custom TextBox so that I can have it bordered, that works fine...
The problem is that I want to set PasswordChar to *, and that doesn't workHere is my code:
public class TextBoxEx : TextBox
{
// The TextBox
private TextBox textBox = new TextBox();
// Border color of the textbox
private Color borderColor = Color.Gray;
// Ctor
public TextBoxEx()
{
this.PasswordChar ='*';
this.Paint += new PaintEventHandler(TextBoxEx_Paint);
this.Resize += new EventHandler(TextBoxEx_Resize);
textBox.Multiline = true;
textBox.BorderStyle = BorderStyle.None;
this.Controls.Add(textBox);
this.UseSystemPasswordChar = true;
InvalidateSize();
}
// Exposed properties of the textbox
public override string Text
{
get { return textBox.Text; }
set { textBox.Text = value; }
}
// ... Expose other properties you need...
// The border color property
public Color BorderColor
{
get { return borderColor; }
set { borderColor = value; Invalidate(); }
}
// Expose the Click event for the texbox
public event EventHandler TextBoxClick
{
add { textBox.Click += value; }
remove { textBox.Click -= value; }
}
// ... Expose other events you need...
private void TextBoxEx_Resize(object sender, EventArgs e)
{
InvalidateSize();
}
private void TextBoxEx_Paint(object sender, PaintEventArgs e)
{
ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle, borderColor, ButtonBorderStyle.Solid);
}
private void InvalidateSize()
{
textBox.Size = new Size(this.Width - 2, this.Height - 2);
textBox.Location = new Point(1, 1);
}
}
Generally when I try to set the properties of custom control by default it doesn't work, for example if I set
this.ReadOnly=true;
This won't work either. So the problem isn't in PasswordChar itself.
Anybody know the solution?
Since the class is itself inheriting the TextBox class, you don't need to create an inner textbox.
With that in mind, you can take out your declaration of private TextBox textBox, and replace references to this member with this, since this is a TextBox descendant.
In the constructor, you will also remove this.Controls.Add(textBox); since there is no longer an inner control to add.
The overridden Text property can also be removed, as it doesn't add functionality to the TextBox definition.
The InvalidateSize method will need to be reworked, since adjusting the Size member triggers the TextBoxEx_Resize handler method, which calls the InvalidateSize method again, eventually causing a StackOverflowException.
One last thing, and an important one. According to MSDN...
If the Multiline property is set to true, setting the PasswordChar property has no visual effect. When the PasswordChar property is set to true, cut, copy, and paste actions in the control using the keyboard cannot be performed, regardless of whether the Multiline property is set to true or false.
Meaning the textbox PasswordCharacter will not display if the textbox is Multiline
Im going to take a stab at this,
private TextBox textBox = new TextBox();
...
this.Controls.Add(textBox);
The above seems to be the problem,
It seems your shadow textbox is actually whats displaying,
If you need shadow properties in the back ground (and without really knowing your goal), probably just best creating the properties you need.

Customizing default inputs?

I wonder if it's possible to customize my C# application (winforms) to get a better design, I made a PSD (photoshop document) so I can generate png jpeg... pictures if I need them.
Example of a form like the one I want :
Indeed as it was pointed out in the comments, it is easy to use WPF (indows Presentation Foundation) to achieve that result, but if you really need that it must be made in windows forms I can help you with that...
ControlBox and Border
It seens that your form does not have a control box (minimize, maximize and close buttons)
to achieve that you can set
form.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
I'm not sure if that galaxy behind your form is part of the application so i'll be considering that it is not
To achieve that irregular shape of the form we have to do a workaround here
Irregular Shape of the Form
we are going to set a Color to TransparentKey, so everything in the form in that specific color will be transparent, like it does not exists (if you click in that part it will go into de desktop or whatever application you have behind in your form)
So let's use a specific color which we will probably dont use in the form
form.TransparencyKey = Color.FromArgb(111, 111, 111); //You can do it by the editor
So in order to make that white part we are going to use an Panel and a PictureBox outsite of the Panel trying to copy the shape of your image
Stylized Inputs
To make it easier and reusable I'm going to make a userControl in this one
the usercontrol will have
a Panel called HighLightPanel, its dock property will be set to Fill
a Panel called BackColorPanel, it will be inside the HighLightPanel
a PictureBox called InputPicture, its dock property will be set to Left, it will be inside BackColorPanel and its acessor will be public
a TextBox called TextBox, its dock property wil be set to fill, it will be inside BackColorPanel, the BorderStyle Property set to None, you should set the size and font you most desize in this one, I'm going to use Segoe UI; 15,75pt and its acessor will be public
Now we have to make some properties in our UserControl to make it work without work in other controls
First in the SizeChanged event of the HighLightPanel we will make the BackColorPanel be exacly two points smaller in every direction and its position to 1;1 so we can see the HighLightPanel
private void HighlightPanel_SizeChanged(object sender, EventArgs e)
{
this.BackColorPanel.Size = new Size(
HighlightPanel.Width - 2,
HighlightPanel.Height - 2);
}
Now we will create two propertys to handle the Highlight Color
public Color HighlightBorderColor { get; set; }
public Color NonHighlightBorderColor { get; set; }
And in the Enter and Leave Property of our TextBox we are going to change the HighlightPanel
private void TextBox_Enter(object sender, EventArgs e)
{
HighlightPanel.BackColor = HighlightBorderColor;
}
private void TextBox_Leave(object sender, EventArgs e)
{
HighlightPanel.BackColor = NonHighlightBorderColor;
}
So now every time the user enter the Input it will appear that the Input has an Border in the specified Color
Now to enhance its usability to developers we will make some wrappers in its controls to be easier change property of child controls in the editor
public Image InputImage
{
get { return InputPicture.Image; }
set { InputPicture.Image = value; }
}
public PictureBoxSizeMode InputImageLayout
{
get { return InputPicture.SizeMode; }
set { InputPicture.SizeMode = value; }
}
public char PasswordCharacter
{
get { return TextBox.PasswordChar; }
set { TextBox.PasswordChar = value; }
}
public bool ShowInputImage
{
get { return InputPicture.Visible; }
set { InputPicture.Visible = value; }
}
In the InputImage set the picture you want for the User and the Key
Insert the two controls in the position you like
Position of the Form
if you want your form to be moveable without the border you will have to use this snippet, it is more easy in WPF
#region MoveForm
Point LastPoint;
bool ShouldMove;
private void form_MouseDown(object sender, MouseEventArgs e)
{
LastPoint = e.Location;
ShouldMove = true;
this.TransparencyKey = Color.FromArgb(111, 111, 111);
}
private void form_MouseUp(object sender, MouseEventArgs e)
{
ShouldMove = false;
}
private void form_MouseMove(object sender, MouseEventArgs e)
{
if (ShouldMove)
{
this.Location = new Point(
this.Location.X - LastPoint.X + e.X,
this.Location.Y - LastPoint.Y + e.Y);
}
}
#endregion
If you need a lot of special graphics effects learning WPF will indeed be a sound investement.
If all you want is that login screen, it is trivial in Winforms and doesn't take any horrible hacks as you've been told..
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.BackColor = System.Drawing.Color.LavenderBlush;
this.TransparencyKey = System.Drawing.Color.LavenderBlush;
this.ControlBox = false;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Text= "";
These seven lines are all it takes for a form to be transparent. I copied them from the Designer code; you can simply set the 7 Properties in the property grid.
Now add a panel, dock it to the bottom and give it the right color; add a picturebox and your other controls and you are set.
To create the two input groups you also need just a few regular controls and only a few simple lines of code:
You place one Panel, BorderStyle = FixedSingle; and add a Label and a TextBox to it. The Label has AutoSize = False; and both ImageAlign and TextAlign are set to MiddleLeft. You assign an image to the Label's Image and prefix the Text with enough blanks to not overlap. Obviously you should define a PasswordChar for the 2nd TextBox. Now all you need is to script the Enter and Leave events to change the BackColor of the respective Panels between, say SystemColors.Control and SystemColors.MenuHighlight. Size the Labels to almost fill the Panels and you are done. Less code than the WPF version, I'd bet.
If you need such input an controls again and again, simply create Usercontrols for each type you need!
Here is an example of the limits you will hit: Wouldn't it be nice to add a dropshadow effect to the image? It is doable in Winforms. But it would involve painting that effect; this would take at least 15 or 20 lines of involved code instead of simply turning the effect on with (estimated) 1-3 simple lines.
Do you need any nice hover effects? Not easy, to say the least..
These limits will be all over the place, so it really depends on how fancy your requirements will get.
Maybe you should use this example as a starter to compare the two techniques and to warm you up to WPF?

.NET Windows Forms mouse enter effect for ALL existing PictureBox controls

I'm new here, and this is my first post here. My apologies if I don't follow the standards on creating a new question here on SO.
I've been racking my brains for the past couple of hours to try to program a custom class which would allow me to add a new property to existing PictureBox controls, allowing me to set a Color to my custom property, which would result in setting a border with the selected color as the user hovers the control.
Below is the code I've written so far:
[ProvideProperty("HoverColor", typeof(PictureBox))]
public class PictureBoxHover : Component, IExtenderProvider
{
private readonly Dictionary<IntPtr, Color> _hoverColors;
public PictureBoxHover()
{
_hoverColors = new Dictionary<IntPtr, Color>();
}
public bool CanExtend(object extendee)
{
return (extendee is PictureBox);
}
public Color GetHoverColor(PictureBox picb)
{
Color color;
if (_hoverColors.TryGetValue(picb.Handle, out color))
return color;
return Color.Empty;
}
public void SetHoverColor(PictureBox picb, Color color)
{
Color hoverColor;
_hoverColors[picb.Handle] = color;
}
}
The above code adds the custom property "HoverColor" to all existing PictureBox controls in my solution - just as I need. All I need to do now is somehow have it draw a border around my PictureBoxes with the set color when the user hovers over the control.
I DON'T want my class to inherit the PictureBox or Control classes, as that would require having to change all my PictureBoxes from the ordinaly PictureBox to my custom PictureBox - which is why I instead want to 'append' this custom property and functionality to the ordinary PictureBox control.
Any help would be greatly appreciated =)
Maybe you could achieve your goal simpler by using custom user control instead of creating extended properties for picture box. Below is a simple sample:
public class FramedPictureBox : UserControl
{
private readonly PictureBox _pictureBox;
public FramedPictureBox()
{
const int FRAME_SIZE = 3;
_pictureBox = new PictureBox
{
Left = FRAME_SIZE,
Top = FRAME_SIZE,
Width = Width - 2*FRAME_SIZE,
Height = Height - 2*FRAME_SIZE,
Anchor = AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Right | AnchorStyles.Top
};
_pictureBox.MouseEnter += OnPictureBoxMouseEnter;
_pictureBox.MouseLeave += OnPictureBoxMouseLeave;
Controls.Add(_pictureBox);
}
protected override void OnLoad(EventArgs e)
{
var image = new Bitmap(_pictureBox.Width, _pictureBox.Height);
var graphics = Graphics.FromImage(image);
graphics.Clear(Color.White);
_pictureBox.Image = image;
base.OnLoad(e);
}
private void OnPictureBoxMouseEnter(object sender, EventArgs e)
{
BackColor = Color.Red;
}
private void OnPictureBoxMouseLeave(object sender, EventArgs e)
{
BackColor = SystemColors.Control;
}
}

Transparent control over PictureBox

In my C# Form I have a Label that displays a download percentage in the download event:
this.lblprg.Text = overallpercent.ToString("#0") + "%";
The Label control's BackColor property is set to be transparent and I want it to be displayed over a PictureBox. But that doesn't appear to work correctly, I see a gray background, it doesn't look transparent on top of the picture box. How can I fix this?
The Label control supports transparency well. It is just that the designer won't let you place the label correctly. The PictureBox control is not a container control so the Form becomes the parent of the label. So you see the form's background.
It is easy to fix by adding a bit of code to the form constructor. You'll need to change the label's Parent property and recalculate it's Location since it is now relative to the picture box instead of the form. Like this:
public Form1() {
InitializeComponent();
var pos = label1.Parent.PointToScreen(label1.Location);
pos = pictureBox1.PointToClient(pos);
label1.Parent = pictureBox1;
label1.Location = pos;
label1.BackColor = Color.Transparent;
}
Looks like this at runtime:
Another approach is to solve the design-time problem. That just takes an attribute. Add a reference to System.Design and add a class to your project, paste this code:
using System.ComponentModel;
using System.Windows.Forms;
using System.Windows.Forms.Design; // Add reference to System.Design
[Designer(typeof(ParentControlDesigner))]
class PictureContainer : PictureBox {}
You can just use
label1.Parent = pictureBox1;
label1.BackColor = Color.Transparent; // You can also set this in the designer, as stated by ElDoRado1239
You can draw text using TextRenderer which will draw it without background:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
TextRenderer.DrawText(e.Graphics,
overallpercent.ToString("#0") + "%",
this.Font,
new Point(10, 10),
Color.Red);
}
When overallpercent value changes, refresh pictureBox:
pictureBox1.Refresh();
You can also use Graphics.DrawString but TextRenderer.DrawText (using GDI) is faster than DrawString (GDI+)
Also look at another answer here and DrawText reference here
For easy for your design.
You can place your label inside a panel. and set background image of panel is what every image you want. set label background is transparent
After trying most of the provided solutions without success, the following worked for me:
label1.FlatStyle = FlatStyle.Standard
label1.Parent = pictureBox1
label1.BackColor = Color.Transparent
You most likely not putting the code in the load function. the objects aren't drawn yet if you put in the form initialize section hence nothing happens.
Once the objects are drawn then the load function runs and that will make the form transparents.
private void ScreenSaverForm_Load(object sender, EventArgs e)
{
label2.FlatStyle = FlatStyle.Standard;
label2.Parent = pictureBox1;
label2.BackColor = Color.Transparent;
}
One way which works for everything, but you need to handle the position, on resize, on move etc.. is using a transparent form:
Form form = new Form();
form.FormBorderStyle = FormBorderStyle.None;
form.BackColor = Color.Black;
form.TransparencyKey = Color.Black;
form.Owner = this;
form.Controls.Add(new Label() { Text = "Hello", Left = 0, Top = 0, Font = new Font(FontFamily.GenericSerif, 20), ForeColor = Color.White });
form.Show();
Using Visual Studio with Windows Form you may apply transparency to labels or other elements by adding using System.Drawing; into Form1.Designer.cs This way you will have Transparency available from the Properties panel ( in Appearance at BackColor ). Or just edit code in Designer.cs this.label1.BackColor = System.Drawing.Color.Transparent;

Resizing Panel Containing UserControl

I have a UserControl that contains invisible controls, to make them visible, the UserControl resizes.
I need to resize the Panel that contains the UserControl, but I don't know how.
This behavior is handled well by the Panel and Form classes without explicit sizing (and without the layout bugs introduced when the user has a high-DPI monitor or uses the large or extra-large font settings.
1) Create a Form with a docked FlowLayoutPanel.
2) Set the Form and FlowLayoutPanel's AutoSize to true and AutoSizeMode to GrowAndShrink
3) Add your panels and content.
4) Programmatically set the desired panel's Visible property to hidden
hiddenPanel.Visible = false;
5) or true
hiddenPanel.Visible = true;
Put this code in the usercontrol:
Size last = new Size(0, 0);
private void Me_Resize(object sender, System.EventArgs e)
{
if (last != new Size(0, 0)) {
this.Parent.Size = Size.Add(this.Parent.Size, Size.Subtract(this.Size, last));
}
last = this.Size;
}
Will also retain margins (e.g., if the panel is larger than your usercontrol or has other controls beside your usercontrol.)
If you'd like to resize it to a particular size, you can do it on the code behind:
Size panelSize = new Size(500, 500);
usercontrol1.Parent.Size = panelSize;
You could add this code to the usercontrol if that is where you wish to resize from.
To resize the control , call scale of to the control.
// To zoom in controls.
foreach (Control c in MyFlowLayoutPanel.Controls)
{
PictureBox ptc = c as PictureBox;
if (null != ptc)
{
Point pt = new Point(2, 2);
SizeF sf = new SizeF(pt);
c.Scale(sf);
}
}
// To zoom out controls.
foreach (Control c in MyFlowLayoutPanel.Controls)
{
PictureBox ptc = c as PictureBox;
if (null != ptc)
{
SizeF sf = new SizeF(0.5F, 0.5F);
c.Scale(sf);
}
}
I know that this topic is pretty old but I want to add my method, as well...
If you have a Panel containing a UserControl you can easially resize the panel.Controls by firing Form1_Resize event.
private void Form1_Resize(object sender, EventArgs e)
{
foreach (Control control in MasterPanel.Controls)
{
control.Size = MasterPanel.Size;
}
}
Just make sure that you anchor its content properly.

Categories