从头开始编写/绘制我自己的ListBox / ListView控件

时间:2014-08-18 11:26:25

标签: c# .net winforms listview gdi+

我如何了解如何制作Windows窗体Control?我想从头开始创建Control。最好是ListBox甚至更好,ListView Control,但我不知道从哪里开始。

我过去遇到过的一些建议是:

  1. 使用Panel Control并使用适当的样式动态添加Label控件;
  2. ListView / ListBox Control进行扩展或子类化,并将OwnerDraw设置为true,并在OnPaint中执行自定义绘图} event。
  3. 但我想要更多的控制权。我不想要ListView Control,我也不想使用第三方控件(无论对象列表视图有多好1我想要我自己的 ListView Control。我不在乎它有多难,但在Windows Forms中这是否可能?我应该从哪里开始?

    我是否需要使用GDI / GDI+来绘制所有内容?我会从空的Panel Control开始,然后使用System.Drawing命名空间手动绘制每个列表项吗?

2 个答案:

答案 0 :(得分:2)

您可以继承Usercontrol并从头开始编写,或者如果您需要listview等特定功能,则可以继承相关控件。

只需谷歌搜索“自定义列表视图控件”或“自定义控件(yourtype)将提供1000的结果”。

希望这有帮助

例如Vista Style按钮的代码:

public class VistaButton : System.Windows.Forms.UserControl
{

    #region -  Designer  -

        private System.ComponentModel.Container components = null;

        /// <summary>
        /// Initialize the component with it's
        /// default settings.
        /// </summary>
        public VistaButton()
        {
            InitializeComponent();

            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.Selectable, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.SetStyle(ControlStyles.UserPaint, true);
            this.BackColor = Color.Transparent;
            mFadeIn.Interval = 30;
            mFadeOut.Interval = 30;
        }

        /// <summary>
        /// Release resources used by the control.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if(components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region -  Component Designer generated code  -

            private void InitializeComponent()
            {
                // 
                // VistaButton
                // 
                this.Name = "VistaButton";
                this.Size = new System.Drawing.Size(100, 32);
                this.Paint += new System.Windows.Forms.PaintEventHandler(this.VistaButton_Paint);
                this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.VistaButton_KeyUp);
                this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.VistaButton_KeyDown);
                this.MouseEnter += new System.EventHandler(this.VistaButton_MouseEnter);
                this.MouseLeave += new System.EventHandler(this.VistaButton_MouseLeave);
                this.MouseUp +=new MouseEventHandler(VistaButton_MouseUp);
                this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.VistaButton_MouseDown);
                this.GotFocus +=new EventHandler(VistaButton_MouseEnter);
                this.LostFocus +=new EventHandler(VistaButton_MouseLeave);
                this.mFadeIn.Tick += new EventHandler(mFadeIn_Tick);
                this.mFadeOut.Tick += new EventHandler(mFadeOut_Tick);
                this.Resize +=new EventHandler(VistaButton_Resize);
            }

        #endregion

    #endregion

    #region -  Enums  -

        /// <summary>
        /// A private enumeration that determines 
        /// the mouse state in relation to the 
        /// current instance of the control.
        /// </summary>
        enum State {None, Hover, Pressed};

        /// <summary>
        /// A public enumeration that determines whether
        /// the button background is painted when the 
        /// mouse is not inside the ClientArea.
        /// </summary>
        public enum Style
        {
            /// <summary>
            /// Draw the button as normal
            /// </summary>
            Default, 
            /// <summary>
            /// Only draw the background on mouse over.
            /// </summary>
            Flat
        };

    #endregion

    #region -  Properties  -

        #region -  Private Variables  -

            private bool calledbykey = false;
            private State mButtonState = State.None;
            private Timer mFadeIn = new Timer();
            private Timer mFadeOut = new Timer();
            private int mGlowAlpha = 0;

        #endregion

        #region -  Text  -

            private string mText;
            /// <summary>
            /// The text that is displayed on the button.
            /// </summary>
            [Category("Text"),
             Description("The text that is displayed on the button.")]
            public string ButtonText
            {
                get { return mText; }
                set { mText = value; this.Invalidate(); }
            }

            private Color mForeColor = Color.White;
            /// <summary>
            /// The color with which the text is drawn.
            /// </summary>
            [Category("Text"), 
             Browsable(true),
             DefaultValue(typeof(Color),"White"),
             Description("The color with which the text is drawn.")]
            public override Color ForeColor
            {
                get { return mForeColor; }
                set { mForeColor = value; this.Invalidate(); }
            }

            private ContentAlignment mTextAlign = ContentAlignment.MiddleCenter;
            /// <summary>
            /// The alignment of the button text
            /// that is displayed on the control.
            /// </summary>
            [Category("Text"), 
             DefaultValue(typeof(ContentAlignment),"MiddleCenter"),
             Description("The alignment of the button text " + 
                         "that is displayed on the control.")]
            public ContentAlignment TextAlign
            {
                get { return mTextAlign; }
                set { mTextAlign = value; this.Invalidate(); }
            }

        #endregion

        #region -  Image  -

            private Image mImage;
            /// <summary>
            /// The image displayed on the button that 
            /// is used to help the user identify
            /// it's function if the text is ambiguous.
            /// </summary>
            [Category("Image"), 
             DefaultValue(null),
             Description("The image displayed on the button that " +
                         "is used to help the user identify" + 
                         "it's function if the text is ambiguous.")]
            public Image Image
            {
                get { return mImage; }
                set { mImage = value; this.Invalidate(); }
            }

            private ContentAlignment mImageAlign = ContentAlignment.MiddleLeft;
            /// <summary>
            /// The alignment of the image 
            /// in relation to the button.
            /// </summary>
            [Category("Image"), 
             DefaultValue(typeof(ContentAlignment),"MiddleLeft"),
             Description("The alignment of the image " + 
                         "in relation to the button.")]
            public ContentAlignment ImageAlign
            {
                get { return mImageAlign; }
                set { mImageAlign = value; this.Invalidate(); }
            }

            private Size mImageSize = new Size(24,24);
            /// <summary>
            /// The size of the image to be displayed on the
            /// button. This property defaults to 24x24.
            /// </summary>
            [Category("Image"), 
             DefaultValue(typeof(Size),"24, 24"),
             Description("The size of the image to be displayed on the" + 
                         "button. This property defaults to 24x24.")]
            public Size ImageSize
            {
                get { return mImageSize; }
                set { mImageSize = value; this.Invalidate(); }
            }

        #endregion

        #region -  Appearance  -

            private Style mButtonStyle = Style.Default;
            /// <summary>
            /// Sets whether the button background is drawn 
            /// while the mouse is outside of the client area.
            /// </summary>
            [Category("Appearance"), 
             DefaultValue(typeof(Style),"Default"),
             Description("Sets whether the button background is drawn " +
                         "while the mouse is outside of the client area.")]
            public Style ButtonStyle
            {
                get { return mButtonStyle; }
                set { mButtonStyle = value; this.Invalidate(); }
            }

            private int mCornerRadius = 8;
            /// <summary>
            /// The radius for the button corners. The 
            /// greater this value is, the more 'smooth' 
            /// the corners are. This property should
            ///  not be greater than half of the 
            ///  controls height.
            /// </summary>
            [Category("Appearance"), 
             DefaultValue(8),
             Description("The radius for the button corners. The " +
                         "greater this value is, the more 'smooth' " +
                         "the corners are. This property should " +
                         "not be greater than half of the " +
                         "controls height.")]
            public int CornerRadius
            {
                get { return mCornerRadius; }
                set { mCornerRadius = value; this.Invalidate(); }
            }

            private Color mHighlightColor = Color.White;
            /// <summary>
            /// The colour of the highlight on the top of the button.
            /// </summary>
            [Category("Appearance"), 
             DefaultValue(typeof(Color), "White"),
             Description("The colour of the highlight on the top of the button.")]
            public Color HighlightColor
            {
                get { return mHighlightColor; }
                set { mHighlightColor = value; this.Invalidate(); }
            }

            private Color mButtonColor = Color.Black;
            /// <summary>
            /// The bottom color of the button that 
            /// will be drawn over the base color.
            /// </summary>
            [Category("Appearance"), 
             DefaultValue(typeof(Color), "Black"), 
             Description("The bottom color of the button that " + 
                         "will be drawn over the base color.")]
            public Color ButtonColor
            {
                get { return mButtonColor; }
                set { mButtonColor = value; this.Invalidate(); }
            }

            private Color mGlowColor = Color.FromArgb(141,189,255);
            /// <summary>
            /// The colour that the button glows when
            /// the mouse is inside the client area.
            /// </summary>
            [Category("Appearance"), 
             DefaultValue(typeof(Color), "141,189,255"), 
             Description("The colour that the button glows when " + 
                         "the mouse is inside the client area.")]
            public Color GlowColor
            {
                get { return mGlowColor; }
                set { mGlowColor = value; this.Invalidate(); }
            }

            private Image mBackImage;
            /// <summary>
            /// The background image for the button, 
            /// this image is drawn over the base 
            /// color of the button.
            /// </summary>
            [Category("Appearance"), 
             DefaultValue(null), 
             Description("The background image for the button, " + 
                         "this image is drawn over the base " + 
                         "color of the button.")]
            public Image BackImage
            {
                get { return mBackImage; }
                set { mBackImage = value; this.Invalidate(); }
            }

            private Color mBaseColor = Color.Black;
            /// <summary>
            /// The backing color that the rest of 
            /// the button is drawn. For a glassier 
            /// effect set this property to Transparent.
            /// </summary>
            [Category("Appearance"), 
             DefaultValue(typeof(Color), "Black"), 
             Description("The backing color that the rest of" + 
                         "the button is drawn. For a glassier " + 
                         "effect set this property to Transparent.")]
            public Color BaseColor
            {
                get { return mBaseColor; }
                set { mBaseColor = value; this.Invalidate(); }
            }

        #endregion

        #region -  Behaviour  -
            private DialogResult mDialogResult = DialogResult.OK;

            /// <summary>
            /// Specify the dialog result property.
            /// </summary>
            [Category("Behaviour"),
                     DefaultValue(typeof(DialogResult)),
                     Description("The Dialog-Box result produced in a modal form" +
                                 "by clicking the button.")]
            public virtual DialogResult DialogResult
            {
                get { return mDialogResult; }
                set { mDialogResult = value; this.Invalidate(); }
            }
            #endregion

    #endregion

    #region -  Functions  -

            private GraphicsPath RoundRect(RectangleF r, float r1, float r2, float r3, float r4)
        {
            float x = r.X, y = r.Y, w = r.Width, h = r.Height;
            GraphicsPath rr = new GraphicsPath();
            rr.AddBezier(x, y + r1, x, y, x + r1, y, x + r1, y);
            rr.AddLine(x + r1, y, x + w - r2, y);
            rr.AddBezier(x + w - r2, y, x + w, y, x + w, y + r2, x + w, y + r2);
            rr.AddLine(x + w, y + r2, x + w, y + h - r3);
            rr.AddBezier(x + w, y + h - r3, x + w, y + h, x + w - r3, y + h, x + w - r3, y + h);
            rr.AddLine(x + w - r3, y + h, x + r4, y + h);
            rr.AddBezier(x + r4, y + h, x, y + h, x, y + h - r4, x, y + h - r4);
            rr.AddLine(x, y + h - r4, x, y + r1);
            return rr;
        }

        private StringFormat StringFormatAlignment(ContentAlignment textalign)
        {
            StringFormat sf = new StringFormat();
            switch (textalign)
            {
                case ContentAlignment.TopLeft:
                case ContentAlignment.TopCenter:
                case ContentAlignment.TopRight:
                    sf.LineAlignment = StringAlignment.Near;
                    break;
                case ContentAlignment.MiddleLeft:
                case ContentAlignment.MiddleCenter:
                case ContentAlignment.MiddleRight:
                    sf.LineAlignment = StringAlignment.Center;
                    break;
                case ContentAlignment.BottomLeft:
                case ContentAlignment.BottomCenter:
                case ContentAlignment.BottomRight:
                    sf.LineAlignment = StringAlignment.Far;
                    break;
            }
            switch (textalign)
            {
                case ContentAlignment.TopLeft:
                case ContentAlignment.MiddleLeft:
                case ContentAlignment.BottomLeft:
                    sf.Alignment = StringAlignment.Near;
                    break;
                case ContentAlignment.TopCenter:
                case ContentAlignment.MiddleCenter:
                case ContentAlignment.BottomCenter:
                    sf.Alignment = StringAlignment.Center;
                    break;
                case ContentAlignment.TopRight:
                case ContentAlignment.MiddleRight:
                case ContentAlignment.BottomRight:
                    sf.Alignment = StringAlignment.Far;
                    break;
            }
            return sf;
        }

    #endregion

    #region -  Drawing  -

        /// <summary>
        /// Draws the outer border for the control
        /// using the ButtonColor property.
        /// </summary>
        /// <param name="g">The graphics object used in the paint event.</param>
        private void DrawOuterStroke(Graphics g)
        {
            Color buttonColor = this.ButtonColor;
            if (!this.Enabled)
                buttonColor = System.Drawing.SystemColors.ControlDark;
            if (this.ButtonStyle == Style.Flat && this.mButtonState == State.None){return;}
            Rectangle r = this.ClientRectangle;
            r.Width -= 1; r.Height -= 1;
            using (GraphicsPath rr = RoundRect(r, CornerRadius, CornerRadius, CornerRadius, CornerRadius))
            {
                using (Pen p = new Pen(buttonColor))
                {
                    g.DrawPath(p, rr);
                }
            }
        }

        /// <summary>
        /// Draws the inner border for the control
        /// using the HighlightColor property.
        /// </summary>
        /// <param name="g">The graphics object used in the paint event.</param>
        private void DrawInnerStroke(Graphics g)
        {
            if (this.ButtonStyle == Style.Flat && this.mButtonState == State.None){return;}
            Rectangle r = this.ClientRectangle;
            r.X++; r.Y++;
            r.Width -= 3; r.Height -= 3;
            using (GraphicsPath rr = RoundRect(r, CornerRadius, CornerRadius, CornerRadius, CornerRadius))
            {
                using (Pen p = new Pen(this.HighlightColor))
                {
                    g.DrawPath(p, rr);
                }
            }
        }

        /// <summary>
        /// Draws the background for the control
        /// using the background image and the 
        /// BaseColor.
        /// </summary>
        /// <param name="g">The graphics object used in the paint event.</param>
        private void DrawBackground(Graphics g)
        {
            Color baseColor = this.BaseColor;
            Color buttonColor = this.ButtonColor;
            if (!this.Enabled)
            {
                baseColor = SystemColors.Control;
                buttonColor = System.Drawing.SystemColors.Control;
            }
            if (this.ButtonStyle == Style.Flat && this.mButtonState == State.None){return;}
            int alpha = (mButtonState == State.Pressed) ? 204 : 127;
            Rectangle r = this.ClientRectangle;
            r.Width--; r.Height--;
            using (GraphicsPath rr = RoundRect(r, CornerRadius, CornerRadius, CornerRadius, CornerRadius))
            {
                using (SolidBrush sb = new SolidBrush(baseColor))
                {
                    g.FillPath(sb, rr);
                }
                SetClip(g);
                if (this.BackImage != null){g.DrawImage(this.BackImage, this.ClientRectangle);}
                g.ResetClip();
                using (SolidBrush sb = new SolidBrush(Color.FromArgb(alpha, buttonColor)))
                {
                    g.FillPath(sb, rr);
                }
            }
        }

        /// <summary>
        /// Draws the Highlight over the top of the
        /// control using the HightlightColor.
        /// </summary>
        /// <param name="g">The graphics object used in the paint event.</param>
        private void DrawHighlight(Graphics g)
        {
            if (this.ButtonStyle == Style.Flat && this.mButtonState == State.None){return;}
            int alpha = (mButtonState == State.Pressed) ? 60 : 150;
            Rectangle rect = new Rectangle(0, 0, this.Width, this.Height / 2);
            using (GraphicsPath r = RoundRect(rect, CornerRadius, CornerRadius, 0, 0))
            {
                using (LinearGradientBrush lg = new LinearGradientBrush(r.GetBounds(), 
                                            Color.FromArgb(alpha, this.HighlightColor),
                                            Color.FromArgb(alpha / 3, this.HighlightColor), 
                                            LinearGradientMode.Vertical))
                {
                    g.FillPath(lg, r);
                }
            }
        }

        /// <summary>
        /// Draws the glow for the button when the
        /// mouse is inside the client area using
        /// the GlowColor property.
        /// </summary>
        /// <param name="g">The graphics object used in the paint event.</param>
        private void DrawGlow(Graphics g)
        {
            if (this.mButtonState == State.Pressed){return;}
            SetClip(g);
            using (GraphicsPath glow = new GraphicsPath())
            {
                glow.AddEllipse(-5,this.Height / 2 - 10, this.Width + 11, this.Height + 11);
                using (PathGradientBrush gl = new PathGradientBrush(glow))
                {
                    gl.CenterColor = Color.FromArgb(mGlowAlpha, this.GlowColor);
                    gl.SurroundColors = new Color[] {Color.FromArgb(0, this.GlowColor)};
                    g.FillPath(gl, glow);
                }
            }
            g.ResetClip();
        }

        /// <summary>
        /// Draws the text for the button.
        /// </summary>
        /// <param name="g">The graphics object used in the paint event.</param>
        private void DrawText(Graphics g)
        {
            Color foreColor = this.ForeColor;
            if (!this.Enabled)
                foreColor = System.Drawing.SystemColors.ControlDark;
            StringFormat sf = StringFormatAlignment(this.TextAlign);
            Rectangle r = new Rectangle(8,8,this.Width - 17,this.Height - 17);
            g.DrawString(this.ButtonText, this.Font, new SolidBrush(foreColor), r, sf);
        }   

        /// <summary>
        /// Draws the image for the button
        /// </summary>
        /// <param name="g">The graphics object used in the paint event.</param>
        private void DrawImage(Graphics g)
        {
            if (this.Image == null) {return;}
            Rectangle r = new Rectangle(8,8,this.ImageSize.Width,this.ImageSize.Height);
            switch (this.ImageAlign)
            {
                case ContentAlignment.TopCenter:
                    r = new Rectangle(this.Width / 2 - this.ImageSize.Width / 2,8,this.ImageSize.Width,this.ImageSize.Height);
                    break;
                case ContentAlignment.TopRight:
                    r = new Rectangle(this.Width - 8 - this.ImageSize.Width,8,this.ImageSize.Width,this.ImageSize.Height);
                    break;
                case ContentAlignment.MiddleLeft:
                    r = new Rectangle(8,this.Height / 2 - this.ImageSize.Height / 2,this.ImageSize.Width,this.ImageSize.Height);
                    break;
                case ContentAlignment.MiddleCenter:
                    r = new Rectangle(this.Width / 2 - this.ImageSize.Width / 2,this.Height / 2 - this.ImageSize.Height / 2,this.ImageSize.Width,this.ImageSize.Height);
                    break;
                case ContentAlignment.MiddleRight:
                    r = new Rectangle(this.Width - 8 - this.ImageSize.Width,this.Height / 2 - this.ImageSize.Height / 2,this.ImageSize.Width,this.ImageSize.Height);
                    break;
                case ContentAlignment.BottomLeft:
                    r = new Rectangle(8,this.Height - 8 - this.ImageSize.Height,this.ImageSize.Width,this.ImageSize.Height);
                    break;
                case ContentAlignment.BottomCenter:
                    r = new Rectangle(this.Width / 2 - this.ImageSize.Width / 2,this.Height - 8 - this.ImageSize.Height,this.ImageSize.Width,this.ImageSize.Height);
                    break;
                case ContentAlignment.BottomRight:
                    r = new Rectangle(this.Width - 8 - this.ImageSize.Width,this.Height - 8 - this.ImageSize.Height,this.ImageSize.Width,this.ImageSize.Height);
                    break;
            }
            g.DrawImage(this.Image,r);
        }

        private void SetClip(Graphics g)
        {
            Rectangle r = this.ClientRectangle;
            r.X++; r.Y++; r.Width-=3; r.Height-=3;
            using (GraphicsPath rr = RoundRect(r, CornerRadius, CornerRadius, CornerRadius, CornerRadius))
            {
                g.SetClip(rr);
            }       
        }

    #endregion

    #region -  Private Subs  -

        private void VistaButton_Paint(object sender, PaintEventArgs e)
        {
                e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
                e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                DrawBackground(e.Graphics);
                DrawHighlight(e.Graphics);
                DrawImage(e.Graphics);
                DrawText(e.Graphics);
                DrawGlow(e.Graphics);
                DrawOuterStroke(e.Graphics);
                DrawInnerStroke(e.Graphics);
        }

        private void VistaButton_Resize(object sender, EventArgs e)
        {
            Rectangle r = this.ClientRectangle;
            r.X -= 1; r.Y -= 1;
            r.Width += 2; r.Height += 2;
            using (GraphicsPath rr = RoundRect(r, CornerRadius, CornerRadius, CornerRadius, CornerRadius))
            {
                this.Region = new Region(rr);
            }
        }

    #region -  Mouse and Keyboard Events  -

        private void VistaButton_MouseEnter(object sender, EventArgs e)
        {
            mButtonState = State.Hover;
            mFadeOut.Stop();
            mFadeIn.Start();
        }
        private void VistaButton_MouseLeave(object sender, EventArgs e)
        {
            mButtonState = State.None;
            if (this.mButtonStyle == Style.Flat) { mGlowAlpha = 0; }
            mFadeIn.Stop();
            mFadeOut.Start();
        }

        private void VistaButton_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                mButtonState = State.Pressed;
                if (this.mButtonStyle != Style.Flat) { mGlowAlpha = 255; }
                mFadeIn.Stop();
                mFadeOut.Stop();
                this.Invalidate();
            }
        }

        private void mFadeIn_Tick(object sender, EventArgs e)
        {
            if (this.ButtonStyle == Style.Flat) {mGlowAlpha = 0;}
            if (mGlowAlpha + 30 >= 255)
            {
                mGlowAlpha = 255;
                mFadeIn.Stop();
            }
            else
            {
                mGlowAlpha += 30;
            }
            this.Invalidate();
        }

        private void mFadeOut_Tick(object sender, EventArgs e)
        {
            if (this.ButtonStyle == Style.Flat) {mGlowAlpha = 0;}
            if (mGlowAlpha - 30 <= 0)
            {
                mGlowAlpha = 0;
                mFadeOut.Stop();
            }
            else
            {
                mGlowAlpha -= 30;
            }
            this.Invalidate();
        }

        private void VistaButton_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Space)
            {
                MouseEventArgs m = new MouseEventArgs(MouseButtons.Left,0,0,0,0);
                VistaButton_MouseDown(sender, m);
            }
        }

        private void VistaButton_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Space)
            {
                MouseEventArgs m = new MouseEventArgs(MouseButtons.Left,0,0,0,0);
                calledbykey = true;
                VistaButton_MouseUp(sender, m);
            }
        }

        private void VistaButton_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left) 
            {
                mButtonState = State.Hover;
                mFadeIn.Stop();
                mFadeOut.Stop();
                this.Invalidate();
                if (calledbykey == true) {this.OnClick(EventArgs.Empty); calledbykey = false;}
            }
        }

    #endregion

    #endregion

}

答案 1 :(得分:2)

  

我将如何了解如何制作Windows窗体控件?

简单,每个控件都是使用Window方法创建的CreateWindowEx(由Winforms内部完成)。

从winforms的角度来看:Control是所有Windows的基类。有些控件是用非托管代码编写的,如ListViewListBox等。对于它们,你无法在.net中看到绘图代码。它是在操作系统本身实现的(不确定他们住的是哪个dll)。 Winforms只提供了那些非托管控件的包装。

但是,有一些用c#编写的纯托管控件。示例:DataGridView。你可以浏览代码。这里的master是OnPaint受保护的方法。在这里,您需要使用提供的Graphics实例编写所有自定义绘制逻辑。

关键是你要创建一个“数据结构”,其中包含绘制控件所需的所有项目。让我们说ItemRectangle,Text,Color,Font等。然后你一起使用它们在OnPaint方法中绘制你的自定义控件。

  

我是否需要使用GDI / GDI +来绘制所有内容?

您将使用System.DrawingSystem.Drawing.Drawing2D命名空间来绘制控件。如果.net没有提供你的东西p / invoke Gdi / Gdi +

选择基类的建议:如果你的控件需要可滚动(ListView那种控件可能需要它)。因此,您可以选择ScrollableControlPanel作为支持滚动的基类。否则,您可以继承Control类。

Developing Custom Windows Forms Controls with the .NET Framework

一切顺利:)