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

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

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

  1. 使用Panel Control并使用适当的样式动态添加Label控件;
  2. 扩展或子类化ListView / ListBox Control ,并将OwnerDraw设置为true ,并在OnPaint事件中执行自定义绘图。

但我想要更多的控制权。 我不只是想要一个ListView Control ,我也不想使用第三方控件(不管有多好[Object ListView]是1.我想要自己的 ListView Control 。我不在乎它有多难是,但这可能在Windows窗体中?我应该从哪里开始?

我需要使用GDI / GDI+来绘制所有内容吗? 我会从一个空的Panel Control ,然后使用System.Drawing命名空间手动绘制每个List Item吗?

我将如何找到如何制作Windows窗体控件?

简单,每个控件都是使用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没有提供的东西你将调用Gdi / Gdi +

选择基类的建议:如果您的控件需要可滚动( ListView类型的控件可能需要它)。 因此,您可以选择ScrollableControl或Panel作为支持滚动的基类。 否则,您可以从Control类inheritance。

使用.NET Framework开发自定义Windows窗体控件

祝一切顺利 :)

您可以inheritanceUsercontrol并从头开始编写,或者如果您需要listview等特定function,则可以inheritance相关控件。

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

希望这可以帮助

例如Vista Style按钮的代码:

 public class VistaButton : System.Windows.Forms.UserControl { #region - Designer - private System.ComponentModel.Container components = null; ///  /// Initialize the component with it's /// default settings. ///  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; } ///  /// Release resources used by the control. ///  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 - ///  /// A private enumeration that determines /// the mouse state in relation to the /// current instance of the control. ///  enum State {None, Hover, Pressed}; ///  /// A public enumeration that determines whether /// the button background is painted when the /// mouse is not inside the ClientArea. ///  public enum Style { ///  /// Draw the button as normal ///  Default, ///  /// Only draw the background on mouse over. ///  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; ///  /// The text that is displayed on the button. ///  [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; ///  /// The color with which the text is drawn. ///  [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; ///  /// The alignment of the button text /// that is displayed on the control. ///  [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; ///  /// The image displayed on the button that /// is used to help the user identify /// it's function if the text is ambiguous. ///  [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; ///  /// The alignment of the image /// in relation to the button. ///  [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); ///  /// The size of the image to be displayed on the /// button. This property defaults to 24x24. ///  [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; ///  /// Sets whether the button background is drawn /// while the mouse is outside of the client area. ///  [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; ///  /// 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. ///  [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; ///  /// The colour of the highlight on the top of the button. ///  [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; ///  /// The bottom color of the button that /// will be drawn over the base color. ///  [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); ///  /// The colour that the button glows when /// the mouse is inside the client area. ///  [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; ///  /// The background image for the button, /// this image is drawn over the base /// color of the button. ///  [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; ///  /// The backing color that the rest of /// the button is drawn. For a glassier /// effect set this property to Transparent. ///  [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; ///  /// Specify the dialog result property. ///  [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 = rX, y = rY, 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 - ///  /// Draws the outer border for the control /// using the ButtonColor property. ///  /// The graphics object used in the paint event. 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); } } } ///  /// Draws the inner border for the control /// using the HighlightColor property. ///  /// The graphics object used in the paint event. 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); } } } ///  /// Draws the background for the control /// using the background image and the /// BaseColor. ///  /// The graphics object used in the paint event. 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); } } } ///  /// Draws the Highlight over the top of the /// control using the HightlightColor. ///  /// The graphics object used in the paint event. 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); } } } ///  /// Draws the glow for the button when the /// mouse is inside the client area using /// the GlowColor property. ///  /// The graphics object used in the paint event. 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(); } ///  /// Draws the text for the button. ///  /// The graphics object used in the paint event. 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); } ///  /// Draws the image for the button ///  /// The graphics object used in the paint event. 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; rX -= 1; rY -= 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 }