设置CircularPictureBox边框颜色

时间:2018-03-26 22:03:02

标签: c# graphics picturebox

我正在创建一个自定义PictureBox。

如您所见,它是专为个人资料照片设计的PictureBox

enter image description here

嗯,这是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;
        }
    }
}

我的问题是,由于它是一个可以从设计师处使用的控件,我希望它具有边缘宽度或边框颜色等属性。

我开始测试颜色,但每当我改变颜色时, Visual Studio向我显示一条错误消息,指出该属性的值无效

1 个答案:

答案 0 :(得分:1)

我对您的代码进行了一些修改,以突出显示在自定义控件设计中有用的一些功能。

我认为我所做的修改是不言自明的 但是,请查看OnPaint事件。 e.Graphics.Clip区域允许您隐藏不在所选区域中的所有图形部分。这意味着当您在设计模式下拖动控件时,图像将被剪裁,并且不会在区域区域外看到。

PixelOffsetMode.HighQualitySmoothingMode.AntiAlias有助于渲染的整体质量(有注释掉的选项可以在其他情况下使用)。

Border偏移的计算必须引用BorderSize宽度,并相应地缩放。 Pen对象从其大小的中间开始绘制。如果笔的大小为3像素,则边框上绘制1个像素,区域外绘制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 pe)
    {
        pe.Graphics.CompositingMode = CompositingMode.SourceOver;
        //pe.Graphics.CompositingQuality = CompositingQuality.HighQuality;
        //pe.Graphics.InterpolationMode = InterpolationMode.Bicubic;
        pe.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
        pe.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

        if (this.Region != null)
            pe.Graphics.Clip = this.Region;
        Rectangle rect = this.ClientRectangle;
        if (this.bitmap != null) 
            pe.Graphics.DrawImage(this.bitmap, rect);

        rect.Inflate(-this.penSize / 2 + 1, -this.penSize / 2 + 1);
        pe.Graphics.DrawEllipse(new Pen(this.borderColor, this.penSize), rect);
    }

    protected override void OnResize(EventArgs e)
    {
        using (GraphicsPath gpath = new GraphicsPath())
        {
            gpath.AddEllipse(this.ClientRectangle);
            gpath.CloseFigure();
            using (Region region = new Region(gpath))
                this.Region = region.Clone();
        }
    }

    [Description("Gets or Sets the Image diplayed by the control."), Category("Appearance")]
    [EditorBrowsable(EditorBrowsableState.Always), Browsable(true)]
    public Bitmap Bitmap
    {
        get { return this.bitmap; }
        set { this.bitmap = value; this.Invalidate(); }
    }

    [Description("Gets or Sets the size of the Border"), Category("Behavior")]
    [EditorBrowsable(EditorBrowsableState.Always), Browsable(true)]
    public int BorderSize
    {
        get { return this.penSize; }
        set { this.penSize = value; this.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 this.borderColor; }
        set { this.borderColor = value; this.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 this.enhancedBuffering; }
        set { this.enhancedBuffering = value; 
              this.SetStyle(ControlStyles.OptimizedDoubleBuffer, value); }
    }

    [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][Category]属性:
(这些已插入您控件的自定义属性BorderColor中。)

    [Description("Gets or Sets the Color of the Border drawn around the Image.")
    [Category("Appearance")]
    [EditorBrowsable(EditorBrowsableState.Always), Browsable(true)]

课程描述向用户解释了该物业的用途 类别用于在PropertyGrid内为属性提供有机配置。您可以使用标准名称(AppearanceBehavior等)或指定其他内容 在Category视图正在使用时,为Categorized提供自定义名称,并在其他名称中列出。

自定义控件的Image属性已隐藏,并替换为Bitmap属性:

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [EditorBrowsable(EditorBrowsableState.Never), BrowsableAttribute(false)]

[EditorBrowsable]属性是Intellisense的提示,可让您确定是否在弹出菜单中显示属性或方法。它可以是NeverAlwaysAdvanced(对于那些知道如何到达VS Options的人)。部署自定义控件(作为dll)时,属性和方法将被隐藏,而不是在设计时隐藏。

[BrowsableAttribute]属性(或仅[Browsable])允许指定是否应在PropertyGrid中显示该属性。

[DesignerSerializationVisibility]

  

使用DesignerSerializationVisibility属性,您可以指出   属性的值是否为 Visible ,并且应该保留   在初始化代码中, Hidden ,不应该保留   初始化代码,或由 Content 组成,应该具有   为每个公共生成的初始化代码,而不是隐藏属性   分配给该属性的对象。

同样有趣并且:
    [TypeConverterAttribute(typeof(System.ComponentModel.ExpandableObjectConverter))]

使用此属性,您可以指示在PropertyGrid中列出类对象的公共属性。
此类对象可以是序列化控件的复杂属性的内部类。 TypeConverter Class本身非常有趣。