Why when adding new properties to custom control the properties not show? - c#

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.

Related

Clear property Text in inerited Button class

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.

Button BorderColor gradient not supporting run time color change?

By using a custom renderer one can create a gradient color effect on the Border of a Button in Xamarin.Forms. Done by editing the BorderColor property in OnElementChanged override method. [Gradient Button credits to #Nico Zhu]
Currently the buttons gradient works on initial start-up. When the border (or StartColor) are changed during run time, the gradient is masked over. See results below. The first is the gradient as shown on load, second shows whats currently selected, and the third is a previously selected button which reverted its border color back to black, but again this still is masking over the initial gradient.
How to support run time changes and maintain the gradient Border on the XF Button?
Xamarin.Forms Gradient Button
using Xamarin.Forms;
namespace XamarinGradientButtonTest
{
public class GradientButton : Button
{
public static readonly BindableProperty StartColorProperty = BindableProperty.Create(
propertyName: "StartColor",
returnType: typeof(Color),
declaringType: typeof(GradientButton),
defaultValue: default(Color));
public Color StartColor
{
get { return (Color)GetValue(StartColorProperty); }
set { SetValue(StartColorProperty, value); }
}
}
}
iOS Renderer
using System;
using CoreAnimation;
using CoreGraphics;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using XamarinGradientButtonTest;
using XamarinGradientButtonTest.iOS;
[assembly: ExportRenderer(typeof(GradientButton), typeof(GradientButtonRenderer))]
namespace XamarinGradientButtonTest.iOS
{
public class GradientButtonRenderer : ButtonRenderer
{
CAGradientLayer gradient;
CAShapeLayer shape;
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
gradient = new CAGradientLayer();
gradient.Colors = new CGColor[] { ((GradientButton)Element).StartColor.ToCGColor(), Element.BorderColor.ToCGColor() };
shape = new CAShapeLayer();
shape.LineWidth = (nfloat)(Element.BorderWidth);
shape.StrokeColor = UIColor.Black.CGColor;
shape.FillColor = UIColor.Clear.CGColor;
gradient.Mask = shape;
Control.Layer.AddSublayer(gradient);
Control.Layer.BorderColor = UIColor.Clear.CGColor;
}
public override void Draw(CGRect rect)
{
base.Draw(rect);
shape.Path = UIBezierPath.FromRect(rect).CGPath;
gradient.Frame = rect;
}
}
}
XF Button Creation
<local:GradientButton BorderColor="Black" BorderRadius="5" StartColor="White" BorderWidth="8" WidthRequest="50" HeightRequest="44" VerticalOptions="Start" HorizontalOptions="Start"/>
On Click
private void btnClick(object sender, EventArgs e)
{
((GradientButton)sender).BorderColor = Color.Green;
}
On De-Select
BorderColor = Color.Black;
You can set the borderColor in the method OnElementPropertyChanged.Add the following code in GradientButtonRenderer
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if(e.PropertyName=="BorderColor")
{
var color = (Element as GradientButton).BorderColor;
gradient.Colors = new CGColor[] { ((GradientButton)Element).StartColor.ToCGColor(), color.ToCGColor() };
shape.StrokeColor = color.ToCGColor();
shape.FillColor = UIColor.Clear.CGColor;
gradient.Mask = shape;
Control.Layer.AddSublayer(gradient);
Control.Layer.BorderColor = UIColor.Clear.CGColor;
}
}

Set CircularPictureBox Border Color

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.

How can I check if the Property value of type Enum in a Custom Control has changed?

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*/
}
}

How to get a C# Custom TextBox to change cursor location on mouse click

I have a custom textbox, which is just a standard textbox with a couple additional small features, and it all works as expected. The problem I am having is that clicking in the field to change the cursor location does not actually change the location of the cursor, the cursor just stays at the beginning of the field.
Below is the code I am working with, I am hoping someone will be able to tell me what I am missing:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Test.UI.Controls
{
public partial class TestTextBox : TextBox
{
private Color normalForegroundColor = Color.Gray;
private Color textChangedForegroundColor = Color.Red;
private string startingText = string.Empty;
[Description("TextBox border color when text is changed"), Category("Appearance")]
public Color TextChangedColor
{
get { return textChangedForegroundColor; }
set { textChangedForegroundColor = value; }
}
[Description("Set starting text of textbox, as well as the Text property"), Category("Appearance")]
public String StartingText
{
get { return startingText; }
set
{
startingText = value;
this.Text = startingText;
}
}
public TestTextBox()
{
InitializeComponent();
normalForegroundColor = this.ForeColor;
}
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
this.ForeColor = this.Text == startingText ? normalForegroundColor : textChangedForegroundColor;
}
}
}
Below is a screen grab of what the custom textbox looks like with data in it:

Categories