I have created a Windows Forms Custom Control inheriting from class Button in order to get a round button:
public partial class RoundButton : Button
{
public RoundButton()
{
InitializeComponent();
Width = 16;
Height = 16;
FlatStyle = FlatStyle.Flat;
FlatAppearance.BorderSize = 0;
BackColor = SystemColors.ControlDark;
}
public sealed override Color BackColor
{
get => base.BackColor;
set => base.BackColor = value;
}
protected override void OnPaint(PaintEventArgs pe)
{
GraphicsPath grPath = new GraphicsPath();
grPath.AddEllipse(0, 0, ClientSize.Width, ClientSize.Height);
Region = new Region(grPath);
base.OnPaint(pe);
}
}
When I add the RoundButton control to a form in the designer its property Text is automatically assigned a value (roundButton1). I have tried to "clear" the property in the constructor, but that doesn't work:
Text = string.Empty;
How do I make sure that the property Text has no value when adding the control in the designer? I don't want to "clear" the property in the Properties window in the designer. The property should be "cleared" by default when added in the designer.
Related
I'm creating a custom PictureBox.
As you can see, it's a PictureBox designed for profile photos
Well, this is the class of the CircularPictureBox
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Hector.Framework.Controls
{
public class CircularPictureBox : PictureBox
{
private Color _idlecolor = Color.White;
public CircularPictureBox()
{
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
this.DoubleBuffered = true;
this.BackColor = Color.White;
this.SizeMode = PictureBoxSizeMode.StretchImage;
this.Size = new Size(100, 100);
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
using (var gpath = new GraphicsPath())
{
var brush = new SolidBrush(this.IdleBorderColor);
var pen = new Pen(brush, 5);
var outrect = new Rectangle(-1, -1, this.Width + 5, this.Height + 5);
gpath.AddEllipse(outrect);
pe.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
pe.Graphics.DrawPath(pen, gpath);
brush.Dispose();
pen.Dispose();
gpath.Dispose();
}
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
using (var gpath = new GraphicsPath())
{
var rect = new Rectangle(1, 1, this.Width - 1, this.Height - 1);
gpath.AddEllipse(rect);
this.Region = new Region(gpath);
gpath.Dispose();
}
}
public Color IdleBorderColor
{
get => this._idlecolor;
set => this._idlecolor = value;
}
}
}
My problem is that since it is a control that can be used from the designer, I want it to have properties such as edge width or border color.
I started testing with the color, but it is that whenever I change the color,
Visual Studio shows me an error message saying that The value of the property is not valid
I made a few modifications to your code, to highlight some features that can be useful in the design of Custom Control.
The modifications I've made I think are self-explanatory.
However, take a look at the OnPaint event. The e.Graphics.Clip Region lets you hide all graphics parts that are not in the selected region. This implies that when you drag the control in Design Mode, the Image will be clipped and won't be seen outside the region area.
The PixelOffsetMode.HighQuality and SmoothingMode.AntiAlias contributes to the overall quality of the rendering (there are commented out options that can useful in other situations).
The calculation of the Border offset must reference the BorderSize width, and scaled accordingly. The Pen object draws starting from the middle of its size. If a Pen has a size of 3 pixels, 1 Pixel is drawn on the border, one outside the area and one inside (weird? Maybe).
The transparency settings is just a "fake" here.
It might be used effectively in other situations (it should read "Platforms").
public class CircularPictureBox : PictureBox
{
private Bitmap bitmap;
private Color borderColor;
private int penSize;
private Color alphaColor = Color.FromArgb(0, 255,255,255);
private bool enhancedBuffering;
public CircularPictureBox()
{
InitializeComponent();
this.SetStyle(ControlStyles.SupportsTransparentBackColor |
ControlStyles.ResizeRedraw |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer, true);
}
private void InitializeComponent()
{
this.enhancedBuffering = true;
this.bitmap = null;
this.borderColor = Color.Silver;
this.penSize = 7;
this.BackColor = alphaColor;
this.SizeMode = PictureBoxSizeMode.StretchImage;
this.Size = new Size(100, 100);
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.CompositingMode = CompositingMode.SourceOver;
//e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
//e.Graphics.InterpolationMode = InterpolationMode.Bicubic;
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
if (this.Region != null) e.Graphics.Clip = this.Region;
var rect = this.ClientRectangle;
if (bitmap != null) {
e.Graphics.DrawImage(bitmap, rect);
}
rect.Inflate(-penSize / 2 + 1, -penSize / 2 + 1);
using (var pen = new Pen(borderColor, penSize)) {
e.Graphics.DrawEllipse(pen, rect);
}
}
protected override void OnResize(EventArgs e)
{
using (var path = new GraphicsPath()) {
path.AddEllipse(this.ClientRectangle);
path.CloseFigure();
using (Region region = new Region(path)) {
this.Region = region.Clone();
}
}
}
[Description("Gets or Sets the Image displayed by the control"), Category("Appearance")]
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true)]
public Bitmap Bitmap
{
get { return bitmap; }
set { bitmap = value; Invalidate(); }
}
[Description("Gets or Sets the size of the Border"), Category("Behavior")]
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true)]
public int BorderSize
{
get { return penSize; }
set { penSize = value; Invalidate(); }
}
[Description("Gets or Sets the Color of Border drawn around the Image.")]
[Category("Appearance")]
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true)]
public Color BorderColor
{
get { return borderColor; }
set { borderColor = value; Invalidate(); }
}
[Description("Enables or disables the control OptimizedDoubleBuffering feature")]
[Category("Useful Features")] //<= "Useful feature" is a custom category
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true)]
public bool EnhancedBuffering
{
get { return enhancedBuffering; }
set { enhancedBuffering = value;
SetStyle(ControlStyles.OptimizedDoubleBuffer, value);
UpdateStyles();
}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
public new Image ErrorImage
{
get { return null; }
set { base.ErrorImage = null; }
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
public new Image InitialImage
{
get { return null; }
set { base.InitialImage = null; }
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
public new Image BackgroundImage
{
get { return null; }
set { base.BackgroundImage = null; }
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never), BrowsableAttribute(false)]
public new Image Image {
get { return null; }
set { base.Image = null; }
}
}
Some System.ComponentModel Attributes that can help shaping the Control.
For example, Description and Category attributes:
(These have been inserted in the custom Property BorderColor of your control).
[Description("Gets or Sets the Color of the Border drawn around the Image.")
[Category("Appearance")]
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true)]
Description of course explains the user what the Property is for.
Category is used to give the Properties an organic disposition inside the PropertyGrid. You can use standard names (Appearance, Behavior etc.) or specify anything else.
Give the Category a custom name and it will be listed among the others, when the Categorized view is in use.
The Image property of the Custom Control has been hidden and substituted with a Bitmap Property:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never), BrowsableAttribute(false)]
The EditorBrowsable Attribute is a hint to Intellisense that lets you determine whether to show a property or method in the Popup menu. It can be Never, Always or Advanced (for those who know how to reach VS Options). Properties and Methods will be Hidden when the Custom Control is deployed (as a dll), not while you are designing it.
The BrowsableAttribute Attribute (or just [Browsable]) allows to specify whether that Property should be shown in the PropertyGrid.
The DesignerSerializationVisibility
With the DesignerSerializationVisibility Attribute, you can indicate
whether the value for a property is Visible, and should be persisted
in initialization code, Hidden, and should not be persisted in
initialization code, or consists of Content, which should have
initialization code generated for each public, not hidden property of
the object assigned to the property.
Also interesting:
TypeConverter(typeof(System.ComponentModel.ExpandableObjectConverter))
With this Attribute, you can instruct to list the Public Properties of a Class Object in the PropertyGrid.
This Class Object can be an internal Class that serializes a complex Property of a Control.
The TypeConverter Class is very interesting itself.
I created a custom control class which inherits from Button.
The reason I did that is I need to create the same Button and I don't want to do everything every single time.
Also, I want a DropDown list selector for the properties that I add, accessible from the Properties Grid in the Form Designer.
For example, I want three different colors and no other, so I want a DropDown selector on for this new Property. I used an Enum for that and it worked, but the problem is when I select for example Red, it doesn't change the color. My code is:
public class CustomButton : Button
{
public NormalColor CLR { get; set; }
public enum NormalColor
{
Red,
Blue,
Yellow
}
public CustomButton()
{
if (CLR == NormalColor.Blue)
{
BackColor = Color.Blue;
}
else if (CLR == NormalColor.Red)
{
BackColor = Color.Red;
}
else if (CLR == NormalColor.Yellow)
{
BackColor = Color.Yellow;
}
else
{
BackColor = Color.FromArgb(18, 18, 18);
}
ForeColor = Color.White;
FlatAppearance.BorderSize = 0;
FlatStyle = FlatStyle.Flat;
Size = new Size(100, 100);
MouseEnter += CustomButton_MouseEnter;
MouseLeave += CustomButton_MouseLeave;
MouseClick += CustomButton_MouseClick;
}
}
In a control Constructor you can define its base (default) properties, not its behaviour or how a Control responds to user settings.
Your Public Properties are delegated to this task.
Note that I've inserted the InitializeComponent() procedure, so the
Control can be dropped in a container from the ToolBox.
If you want to hide your Control's BackColor Property in the Property window at Design Time, override the property and hide it with:
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
You could change your CustomButton this way:
(With the current settings, when you drop your control on a Form from the Toolbox, it will be drawn with a red BackColor and a white ForeColor).
public class CustomButton : Button
{
private NormalColor CurrentColorSelection = 0;
public NormalColor CLR
{
get { return CurrentColorSelection; }
set { SetBackColor(value); }
}
public enum NormalColor
{
Red,
Blue,
Yellow
}
public CustomButton() => InitializeComponent();
private void InitializeComponent()
{
SetBackColor(CurrentColorSelection);
this.ForeColor = Color.White;
this.FlatAppearance.BorderSize = 0;
this.FlatStyle = FlatStyle.Flat;
this.Size = new Size(100, 100);
this.MouseEnter += this.CustomButton_MouseEnter;
this.MouseLeave += this.CustomButton_MouseLeave;
this.MouseClick += this.CustomButton_MouseClick;
}
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
public override Color BackColor
{
get { return base.BackColor; }
set { base.BackColor = value; }
}
private void SetBackColor(NormalColor value)
{
this.CurrentColorSelection = value;
this.BackColor = Color.FromName(value.ToString());
}
//(...)
//Event Handlers
}
When you instantiate the button class constructor is executed first, so in your code flow make sure that CLR is set while instantiating
Do following
public class CustomButton : Button
{
public NormalColor CLR
{
get;
private set;
}
public enum NormalColor
{
Red,
Blue,
Yellow
}
#region Constructor
public CustomButton(NormalColor backgroundColor)
{
CLR = backgroundColor;
if (CLR == NormalColor.Blue)
{
BackColor = Color.Blue;
}
/*Your other code*/
}
}
I need to alternate the color of the items in my CheckedListBox but "alternatingColors" is not a property of CheckedListBox.
How do I go about making the item's colors alternate?
The OnDrawItem event is inaccessible by default, but if you derive a new control based on CheckedListBox, then you can override the base event.
public class MyCheckedListBox : CheckedListBox
{
private SolidBrush primaryColor = new SolidBrush(Color.White);
private SolidBrush alternateColor = new SolidBrush(Color.LightGreen);
[Browsable(true)]
public Color PrimaryColor
{
get { return primaryColor.Color; }
set { primaryColor.Color = value; }
}
[Browsable(true)]
public Color AlternateColor
{
get { return alternateColor.Color; }
set { alternateColor.Color = value; }
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
base.OnDrawItem(e);
if (Items.Count <= 0)
return;
var contentRect = e.Bounds;
contentRect.X = 16;
e.Graphics.FillRectangle(e.Index%2 == 0 ? primaryColor : alternateColor, contentRect);
e.Graphics.DrawString(Convert.ToString(Items[e.Index]), e.Font, Brushes.Black, contentRect);
}
}
It'll alternate between white and green by default. Make adjustments in the Properties panel at design time, or during runtime.
I don't think this is even possible. You may want to consider using a different control for what you need. A DataGridView might be able to work for you better.
I have a library class and i added a new User Control and added a code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CustomControl
{
public partial class ExtendedTextBox : UserControl
{
[PropertyTab("Data")]
[Browsable(true)]
[Category("Extended Properties")]
[Description("Set TextBox border Color")]
public string Texts
{
get { return textBox.Text; }
set { textBox.Text = value; }
}
private TextBox textBox;
public ExtendedTextBox()
{
InitializeComponent();
textBox = new TextBox();
textBox.Multiline = true;
textBox.BorderStyle = BorderStyle.None;
this.Controls.Add(textBox);
}
private void ExtendedTextBox_Load(object sender, EventArgs e)
{
}
private void ExtendedTextBox_Paint(object sender, PaintEventArgs e)
{
ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle, Color.Red, ButtonBorderStyle.Solid);
}
private void ExtendedTextBox_Resize(object sender, EventArgs e)
{
textBox.Size = new Size(this.Width - 3, this.Height - 2);
textBox.Location = new Point(2, 1);
}
}
}
When i add the dll file to another windows forms project i drag the control to the designer but in the solution explorer under the control properties i don't see Data and not Extended Properties and not Set TextBox border Color.
I wanted to add a property that when you click on it will give you a sub property and click on that will open the colors pattern so you can change/set a new color to the paint event.
Now in the paint event it's set to Red but i want that there will be a property so the user can set any color.
Not so understand what you tried. But works great for me, after some changes are needed in your code.
public partial class ExtendedTextBox : UserControl
{
[PropertyTab("Data")]
[Browsable(true)]
[Category("Extended Properties")]
[Description("Set TextBox border Color")]
public Color BorderColor { get; set; }
[PropertyTab("Data")]
[Browsable(true)]
[Category("Extended Properties")]
[Description("Set TextBox Text")]
public string Texts
{
get { return textBox.Text; }
set { textBox.Text = value; }
}
private TextBox textBox;
public ExtendedTextBox()
{
textBox = new TextBox();
textBox.Multiline = true;
textBox.BorderStyle = BorderStyle.None;
this.Controls.Add(textBox);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle, BorderColor, ButtonBorderStyle.Solid);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
textBox.Size = new Size(this.Width - 3, this.Height - 2);
textBox.Location = new Point(2, 1);
}
}
EDIT: For apply changes immediately
you need refresh the control BorderColor property on catch the moment of set, which is not possible automatic property, but only full property. so:
//private field needy in full property.
private Color _BorderColor = Color.Red; //= Color.Red; for default color...
[PropertyTab("Data")]
[Browsable(true)]
[Category("Extended Properties")]
[Description("Set TextBox border Color")]
public Color BorderColor
{
get {return _BorderColor ;}
set
{
_BorderColor = value;
Invalidate(); //refresh, trigger new paint.
}
}
Where is property that stores textBox border color? I see only public string Texts property. You should add new property for textBox border:
[PropertyTab("Data")]
[Browsable(true)]
[Category("Extended Properties")]
[Description("Set TextBox border Color")]
public Color BorderColor { get; set; }
Where are you defining the Data class that inherits PropertyTab? If you are not defining it yourself, what Data class did you expect for the designer to use?
The other attributes — Category and Description — work fine for me. The custom property is shown in the "Properties" tab of the PropertyGrid control, in its own "Extended Properties" category (naturally, you have to be grouping properties by category, not alphabetically), with the correct description text (shown when the property is selected in the PropertyGrid).
The PropertyTab attribute has to specify a valid PropertyTab class. If you don't have a Data class for it to use, then obviously the property can't be displayed in the Data class's property tab.
I have a form with a menu and a toolstrip at the top. The menuStrip has a nice looking gradient background, how can I get the same effect on the toolStrip control? I know about the RenderMode property but changing this doesn't have the desired result.
You can achieve this with a custom renderer.
public class CustomToolStripRenderer : ToolStripProfessionalRenderer
{
public CustomToolStripRenderer() { }
protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
{
//you may want to change this based on the toolstrip's dock or layout style
LinearGradientMode mode = LinearGradientMode.Horizontal;
using (LinearGradientBrush b = new LinearGradientBrush(e.AffectedBounds, ColorTable.MenuStripGradientBegin, ColorTable.MenuStripGradientEnd, mode))
{
e.Graphics.FillRectangle(b, e.AffectedBounds);
}
}
}
Then set your toolstrip to use an instance of this renderer.
public Form1()
{
InitializeComponent();
CustomToolStripRenderer r = new CustomToolStripRenderer();
r.RoundedEdges = false;
toolStrip1.Renderer = r;
}