设置圆形图片框边框颜色
Set CircularPictureBox Border Color
我正在创建自定义 PictureBox。
如你所见,这是一个专为个人资料照片设计的图片框
嗯,这是 CircularPictureBox
的 class
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;
}
}
}
我的问题是因为它是一个可以从设计器中使用的控件,所以我希望它具有边缘宽度或边框颜色等属性。
我开始测试颜色,但每当我改变颜色时,
Visual Studio 向我显示一条错误消息,指出 属性 的值无效
我对您的代码进行了一些修改,以突出一些可用于自定义控件设计的功能。
我认为我所做的修改是self-explanatory。
但是,请看一下 OnPaint
事件。 e.Graphics.Clip
区域可让您隐藏所有不在所选区域中的图形部分。这意味着当您在设计模式下拖动控件时,图像将被剪裁并且不会在区域区域之外看到。
PixelOffsetMode.HighQuality and SmoothingMode.AntiAlias 有助于提高渲染的整体质量(有注释掉的选项在其他情况下很有用)。
Border 偏移量的计算必须参考 BorderSize 宽度,并相应地缩放。 Pen 对象从其大小的中间开始绘制。如果 Pen 的大小为 3 个像素,则在边框上绘制 1 个像素,一个在区域外,一个在区域内(很奇怪?也许吧)。
这里的透明度设置只是一个“假”。
它可能在其他情况下有效使用(应该读作“平台”)。
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; }
}
}
一些 System.ComponentModel
有助于塑造控件的属性。
例如Description and Category属性:
(这些已插入您控件的自定义 属性 BorderColor
)。
[Description("Gets or Sets the Color of the Border drawn around the Image.")
[Category("Appearance")]
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true)]
Description 当然是向用户解释 属性 的用途。
类别用于为属性提供 PropertyGrid 内的有机配置。您可以使用标准名称(Appearance
、Behavior
等)或指定任何其他名称。
给 Category
一个自定义名称,当 Categorized
视图正在使用时,它将与其他名称一起列出。
自定义控件的 Image
属性 已被隐藏并替换为 Bitmap
属性:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never), BrowsableAttribute(false)]
EditorBrowsable Attribute 是对 Intellisense 的提示,它让您决定是否在弹出菜单中显示 属性 或方法。它可以是Never
、Always
或Advanced
(对于那些知道如何到达VS Options
的人)。部署自定义控件(作为 dll)时属性和方法将被隐藏,而不是在您设计它时隐藏。
BrowsableAttribute 属性(或仅 [Browsable]
)允许指定 属性 是否应显示在 属性 网格中。
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.
也很有趣:
TypeConverter(typeof(System.ComponentModel.ExpandableObjectConverter))
使用此属性,您可以指示在 属性 网格中列出 Class 对象的 Public 属性。
此 Class 对象可以是一个内部 Class,它序列化一个复杂的 属性 控件。
TypeConverter Class本身就很有趣。
我正在创建自定义 PictureBox。
如你所见,这是一个专为个人资料照片设计的图片框
嗯,这是 CircularPictureBox
的 classusing 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;
}
}
}
我的问题是因为它是一个可以从设计器中使用的控件,所以我希望它具有边缘宽度或边框颜色等属性。
我开始测试颜色,但每当我改变颜色时, Visual Studio 向我显示一条错误消息,指出 属性 的值无效
我对您的代码进行了一些修改,以突出一些可用于自定义控件设计的功能。
我认为我所做的修改是self-explanatory。
但是,请看一下 OnPaint
事件。 e.Graphics.Clip
区域可让您隐藏所有不在所选区域中的图形部分。这意味着当您在设计模式下拖动控件时,图像将被剪裁并且不会在区域区域之外看到。
PixelOffsetMode.HighQuality and SmoothingMode.AntiAlias 有助于提高渲染的整体质量(有注释掉的选项在其他情况下很有用)。
Border 偏移量的计算必须参考 BorderSize 宽度,并相应地缩放。 Pen 对象从其大小的中间开始绘制。如果 Pen 的大小为 3 个像素,则在边框上绘制 1 个像素,一个在区域外,一个在区域内(很奇怪?也许吧)。
这里的透明度设置只是一个“假”。
它可能在其他情况下有效使用(应该读作“平台”)。
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; }
}
}
一些 System.ComponentModel
有助于塑造控件的属性。
例如Description and Category属性:
(这些已插入您控件的自定义 属性 BorderColor
)。
[Description("Gets or Sets the Color of the Border drawn around the Image.")
[Category("Appearance")]
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true)]
Description 当然是向用户解释 属性 的用途。
类别用于为属性提供 PropertyGrid 内的有机配置。您可以使用标准名称(Appearance
、Behavior
等)或指定任何其他名称。
给 Category
一个自定义名称,当 Categorized
视图正在使用时,它将与其他名称一起列出。
自定义控件的 Image
属性 已被隐藏并替换为 Bitmap
属性:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never), BrowsableAttribute(false)]
EditorBrowsable Attribute 是对 Intellisense 的提示,它让您决定是否在弹出菜单中显示 属性 或方法。它可以是Never
、Always
或Advanced
(对于那些知道如何到达VS Options
的人)。部署自定义控件(作为 dll)时属性和方法将被隐藏,而不是在您设计它时隐藏。
BrowsableAttribute 属性(或仅 [Browsable]
)允许指定 属性 是否应显示在 属性 网格中。
DesignerSerializationVisibility
With the
DesignerSerializationVisibility
Attribute, you can indicate whether the value for a property isVisible
, and should be persisted in initialization code,Hidden
, and should not be persisted in initialization code, or consists ofContent
, which should have initialization code generated for each public, not hidden property of the object assigned to the property.
也很有趣:
TypeConverter(typeof(System.ComponentModel.ExpandableObjectConverter))
使用此属性,您可以指示在 属性 网格中列出 Class 对象的 Public 属性。
此 Class 对象可以是一个内部 Class,它序列化一个复杂的 属性 控件。
TypeConverter Class本身就很有趣。