What is the best way to create customized Windows Form controls? - c#

I'm making C# Windows Form application that has many forms that use many textboxes and labels of the same properties and style.
Instead of changing properties of every textbox and every label I created class called MyTextBox that inherits from System.Windows.Forms.TextBox and then changed its properties in class constructor like this:
class MyTextBox:TextBox
{
public MyTextBox()
{
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.Font = new System.Drawing.Font("Bookman Old Style", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.ForeColor = System.Drawing.Color.Blue;
this.Size = new System.Drawing.Size(257, 23);
}
}
After building project class appeared in toolbox and by making instances from this class on my form it worked fine.
The problem is that when I change any of the properties in MyTextBox class and rebuilding project, changes do not apply to the already instanced objects and when I looked at the designer code, I found that the IDE copied all properties from MyTextBox class to the designer code so I have to recreate all my instances after any change to class code.
private void InitializeComponent()
{
this.MyTextBox1 = new WindowsFormsApplication9.MyTextBox();
this.SuspendLayout();
//
// MyTextBox1
//
this.MyTextBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.MyTextBox1.Font = new System.Drawing.Font("Bookman Old Style", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.MyTextBox1.ForeColor = System.Drawing.Color.Blue;
this.MyTextBox1.Location = new System.Drawing.Point(67, 43);
Any way to solve this problem? I want any changes to the class code applied to all already instanced objects without need to recreate them or if there is a better way please help.
Suppose I need to be controlling 5 properties of MyTextBox instance like ForeColor,default Width, default Font Style , default Font size and BorderStyle. All of them except Width property are not supposed to have other value than default value.

First you should provide suitable default values for properties in constructor. Then you should override or shadow properties and decorate them with one of these attributes:
[DefaultValue]
The designer will serialize these properties only if the value of theme is different than the default value which you set in the attribute.
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
The designer will not serialize values of these properties.
Code
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
public partial class MyTextBox : TextBox
{
public MyTextBox()
{
this.ForeColor = Color.Red;
this.Font = new Font("Tahoma", 9, FontStyle.Italic);
this.Width = 200;
}
[DefaultValue(typeof(Color), "Red")]
public override Color ForeColor
{
get { return base.ForeColor; }
set { base.ForeColor = value; }
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override Font Font
{
get { return base.Font; }
set { base.Font = value; }
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new Size Size
{
get { return base.Size; }
set { base.Size = value; }
}
}
In the above example, I created a custom TextBox having these features:
The default value for ForeColor is Color.Red. If you change value of ForeColor in instances of the control, the value will be serialized. If you change the default value in class, only those instances which their ForeColor was untouched will use new default value, other instances will use their ForeColor value.
The default value for Font is new Font("Tahoma", 9, FontStyle.Italic) and since we said to the designer to not serialize Font property, the new value for property will not be saved if you change the value of different instances and all instances will use default value which is set in constructor of MyTextBox.
For setting default Width which user can not change it using designer, I overrided Size and said the designer to not serialize it, so the width will be set to the default Width which I set in constructor.

A settings file should do what you want. Create a new settings file in your project, if one doesn't exist already, and add a new setting like this:
then in your custom TextBox override OnCreateControl
protected override void OnCreateControl() {
base.OnCreateControl();
ForeColor = Settings.Default.TextBox_ForeColor;
}
Now you can change ForeColor in the settings file and the changes will cascade to all instances of your custom TextBox. Follow the same pattern for Font, Size, etc, just be sure to set the correct Type in the settings file.

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.

Store font of button in the constructor

I have a customized button deriving from System.Windows.Forms.Button:
(class MyButton : Button)
This button has an extra property called IsSelected.
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
if (value)
this.Font = new Font(_storedFont.FontFamily, _storedFont.Size - 1); //Decrease font size by 1
else
this.Font = _storedFont; //Set font back to origin
}
}
If IsSelected is set true the font size of the button will be decreased by 1 point to show the user of the application, that this button is in "pressed" state.
If IsSelected is set false the font size of the button will be set back to original size to show the user that this button is now again in "normal" state.
The issue is now that I first need to store the original font size that has been set in the properties window in Visual Studio, before it is changed by IsSelected.
To hold the stored original font size I have property called StoredFont (class level field = _storedFont).
I then tried to store the original font size in a chained constructor in MyButton, but it appears that the constructor is called before Visual Studio has actually set the font that has been defined in the properties window.
Question 1:
Is it correct that the constructor is called before Visual Studio actually sets the font?
Question 2:
Any suggestions to how to save the font that has been set from the properties window when a new instance of MyButton is created?
Note!
I have already considered many other possibilities to show selected state (CheckBox instead of Button, other back color etc.), and this is not my question.
Thanks a lot in advance!
Question 1: Yes otherwise you'll endup with a NullReferenceException...
Question 2: Assuming the first Font assignment is the font you want to store, you could store the font in an override of Font
public override Font Font
{
get
{
return base.Font;
}
set
{
if(_storedFont == null)
_storedFont = Font;
base.Font = value;
}
}
This way you don't have to worry about the order of initialization.

UserControl Shows Property in Visual Studio Designer, But Property Is Not Changed

So today, I decided to create a custom TextButton control in C# using Visual Studio 2012. I quite like the design I've made, simple as it may be. However, when I decided I would move my completed component into a form using the Visual Studio Designer, I ran into a snag. Although the Text property shows up in the properties list, the property is not not actually being changed in the MainWindow.Designer.cs file. Below is the code that defines the property:
[Category("Appearance")]
[Description("The text displayed by the control.")]
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
public override string Text
{
get
{
return Button.Text;
}
set
{
Button.Text = value;
}
}
And here is the code that my MainWindow.Designer.cs file is creating in the InitializeComponent method:
this.Open = new UI.Controls.TextButton();
this.Open.Location = new System.Drawing.Point(9, 3);
this.Open.Name = "Open";
this.Open.Size = new System.Drawing.Size(112, 28);
this.Open.TabIndex = 4;
this.Open.Click += new System.EventHandler(this.OpenButton_Click);
Part of the problem is that you are overriding the UserControl's Text Property. If you name your property another name besides Text such as myText it will work. In order to fix the problem you have using Text try adding the DesignerSerializationVisibility Attribute to your Property, that should take care of it.
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]

How-To set Height of a Textbox?

For my single line Textbox, I set is Border = None. On doing this, the height turns very small. I can't programamtically set the height of the textbox. If I set any border, then again its fine, but I don't want any border. Even the text is not visible completely - so the font size is already bigger the the textbox height.
I tried creating a custom textbox, and set the Height of it, but it has no effect. How to handle this situation? Any help is highly appreciated.
There is a simple way not to create a new class.
In Designer.cs file:
this.textBox1.AutoSize = false;
this.textBox1.Size = new System.Drawing.Size(228, 25);
And that's all.
TextBox derives from Control, which has an AutoSize property, but the designers have hidden the property from the PropertyGrid and Intellisense, but you can still access it:
public class TextBoxWithHeight : TextBox {
public TextBoxWithHeight() {
base.AutoSize = false;
}
}
Rebuild and use.
TextBox controls automatically resize to fit the height of their Font, regardless of the BorderStyle you choose. That's part of the defaults used by Visual Studio.
By changing the Multiline, you can override the Height.
this.textBox1.Font = new System.Drawing.Font("Microsoft Sans Serif",
26.25F,
System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point,
((byte)(0)));
this.textBox1.Location = new System.Drawing.Point(373, 502);
// this is what makes the height 'stick'
this.textBox1.Multiline = true;
// the desired height
this.textBox1.Size = new System.Drawing.Size(100, 60);
Hope this helps.
I just created this case in an empty project and don't see the result you are describing.
When the BorderStyle is none, the display area of the Textbox auto-sizes to the font selected. If I then set Multiline = true, I can change the height portion of the Size property and the change sticks.
Perhaps another portion of your code is modifying the height? A resize event handler perhaps?
My suggestions:
Post the relevant portions of your code
Try to reproduce the issue in an empty WinForms project (as I just did)
I find the best solution is to subclass the Textbox and expose the hidden AutoSize there:
public class TextBoxWithHeight : TextBox
{
public bool Auto_Size
{
get { return this.AutoSize; }
set { this.AutoSize = value; }
}
}
Now you can set the Autosize on or off using the object inspector in the visual designer or in code, whatever you prefer.
Just select your textbox and go to properties then increase your font size.. DONE !!!

How can I tell Visual Studio to not populate a field in the designer code?

I have a custom control that when I drag onto the form, creates the following designer.cs code:
//
// colorPickerBackground
//
this.colorPickerBackground.Color = Color.Empty;
this.colorPickerBackground.Location = new System.Drawing.Point(256, 175);
this.colorPickerBackground.Name = "colorPickerBackground";
this.colorPickerBackground.Size = new System.Drawing.Size(156, 21);
this.colorPickerBackground.TabIndex = 17;
this.colorPickerBackground.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(this.colorPicke
I'd like it (Visual Studio) to completely ignore the .Color attribute and leave it be. How can I tell it to do that?
Thank you!
You can derive a new class from the ColorPickerBackground class. Override (or new) the Color property and decorate with the attributes found in System.ComponentModel...
Take a look at these:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public Color Color { get; set; }
http://msdn.microsoft.com/en-us/library/system.componentmodel.designerserializationvisibilityattribute.aspx
http://msdn.microsoft.com/en-us/library/system.componentmodel.browsableattribute.aspx
http://msdn.microsoft.com/en-us/library/system.componentmodel.editorbrowsableattribute.aspx

Categories