C# 文本框自定义onPaint

C# 文本框自定义onPaint,c#,winforms,C#,Winforms,我正在尝试为我的文本框创建自定义onPaint,它正在工作。。。但是当我试着输入一些东西时 这是我的构造器: public TextBox() { Font = new Font("Segoe UI", 11F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0))); BackColor = Color.White; BorderColor = Color.Gray; BorderStyle = BorderStyle.None;

我正在尝试为我的文本框创建自定义onPaint,它正在工作。。。但是当我试着输入一些东西时

这是我的构造器:

public TextBox()
{
  Font = new Font("Segoe UI", 11F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
  BackColor = Color.White;
  BorderColor = Color.Gray;
  BorderStyle = BorderStyle.None;
  SetStyle(ControlStyles.UserPaint, true);
}
和onPaint:

protected override void OnPaint(PaintEventArgs e)
{
  Graphics g = e.Graphics;
  g.FillRectangle(backgroundBrush, 0, 0, this.Width, this.Height);

  SizeF fontSize = g.MeasureString(Text, Font);
  g.DrawString(Text, Font, new SolidBrush(ForeColor), new PointF(5, 5), cFormat);

  g.DrawRectangle(borderPen, borderPen.Width / 2, borderPen.Width / 2,
                  this.Width - borderPen.Width, this.Height - borderPen.Width);
}

如果您只需要一个带有自定义边框(宽度和颜色)的自定义
文本框,我这里有两个解决方案:

  • 使用
    ControlPaint
    ,这将允许您使用某种样式和颜色绘制边框,但不能使用
    画笔
    绘制更多不同的边框(如
    掀背画笔
    可以做到):

    以下是文本框快照:

  • 使用
    图形的
    填充区域
    方法
    用各种
    画笔
    绘制边框,这里我使用
    阴影画笔

    public class CustomTextBox : TextBox
    {
      [DllImport("user32")]
      private static extern IntPtr GetWindowDC(IntPtr hwnd);
      struct RECT
      {
        public int left, top, right, bottom;
      }
      struct NCCALSIZE_PARAMS
      {
        public RECT newWindow;
        public RECT oldWindow;
        public RECT clientWindow;
        IntPtr windowPos;
      }         
      int clientPadding = 2;   
      int actualBorderWidth = 4;     
      protected override void WndProc(ref Message m)
      {
          //We have to change the clientsize to make room for borders
          //if not, the border is limited in how thick it is.
          if (m.Msg == 0x83) //WM_NCCALCSIZE   
          {
            if (m.WParam == IntPtr.Zero)
            {
                RECT rect = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
                rect.left += clientPadding;
                rect.right -= clientPadding;
                rect.top += clientPadding;
                rect.bottom -= clientPadding;
                Marshal.StructureToPtr(rect, m.LParam, false);
            }
            else
            {
                NCCALSIZE_PARAMS rects = (NCCALSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(NCCALSIZE_PARAMS));
                rects.newWindow.left += clientPadding;
                rects.newWindow.right -= clientPadding;
                rects.newWindow.top += clientPadding;
                rects.newWindow.bottom -= clientPadding;
                Marshal.StructureToPtr(rects, m.LParam, false);
            }
          }
          if (m.Msg == 0x85) //WM_NCPAINT
          {                 
            IntPtr wDC = GetWindowDC(Handle);
            using(Graphics g = Graphics.FromHdc(wDC)){                                                
              Rectangle rect = new Rectangle(0,0,Width,Height);
              Rectangle inner = new Rectangle(0, 0, Width, Height);
              inner.Offset(actualBorderWidth + 2, actualBorderWidth + 2);
              inner.Width -= 2 * actualBorderWidth + 4;
              inner.Height -= 2 * actualBorderWidth + 4;
              Region r = new Region(rect);
              r.Xor(inner);
              using (System.Drawing.Drawing2D.HatchBrush brush = new System.Drawing.Drawing2D.HatchBrush(System.Drawing.Drawing2D.HatchStyle.SmallCheckerBoard, Color.Green, Color.Red))
              {                    
                g.FillRegion(brush, r);
              }
            }
            return;
          }
          base.WndProc(ref m);
      }
    }
    
    以下是文本框快照:


  • TextBox控件不使用Paint事件,因此您可以看到该控件的版本和您自己的版本。对,所以我确实需要创建自己的控件?或者还有其他方法吗?如果您只想制作边框,请尝试将文本框放在一个带有2像素填充的面板中,并将文本框设置为Dock.Fill and MultiLine=true。否则,我们不清楚您为什么要尝试绘制文本框。@LarsTech我们想要一个带有自定义边框颜色的文本框。@再次提醒您,我想知道为什么您喜欢在认为Winforms已经死了的情况下参与
    Winforms
    问题。说服人们让
    winforms
    早点死?我认为你不必那么做。许多人肯定会认识到
    WPF
    更适合他们。我还跟你打赌,
    WPF
    将是我下一个商业项目的选择。不过,我仍将学习Winforms以练习其他技能,如GDI+、Win32。。。只是为了好玩。我尝试了代码,但没有成功:System.ArgumentException未经处理,参数无效。第62行(g.ReleaseHdc(wDC))。它还说它不能将float转换为int,所以我将actualOrderWidth更改为int。@gerard哪个代码不起作用?第一个还是第二个?
    ActualOrderWidth
    应该在第二个代码中声明为
    int
    ,我更新了它,很抱歉,但是在第一个代码中它应该是
    float
    @gerard请查看我的更新,只需删除行
    g.ReleaseHdc…
    并添加行
    return。我不知道它以前为什么工作,但在这种情况下,我们不需要ReleaseDC,如果您想使用
    ReleaseDC
    win32 api函数,它不会引发任何异常。
    返回才能不执行默认的非客户端区域绘制。@gerard此代码泄漏严重。您需要使用,而不是
    .G.ReleaseHdc
    ,并将其称为
    ReleaseDC(Handle,wDC)处理图形对象后,应使用
    分支将其包装在
    中,
    使用(Graphics g=Graphics.FromHdc(wDC)){…}
    。我认为(我可能错了),但是返回语句可能会阻止
    base.WndProc(refm)方法:我不认为你总是在Vista或Win7上的多行框中绘制滚动条。不要忽略关于ReleaseDC的建议。您正在泄漏当前代码的句柄。
    
    public class CustomTextBox : TextBox
    {
      [DllImport("user32")]
      private static extern IntPtr GetWindowDC(IntPtr hwnd);
      struct RECT
      {
        public int left, top, right, bottom;
      }
      struct NCCALSIZE_PARAMS
      {
        public RECT newWindow;
        public RECT oldWindow;
        public RECT clientWindow;
        IntPtr windowPos;
      }         
      int clientPadding = 2;   
      int actualBorderWidth = 4;     
      protected override void WndProc(ref Message m)
      {
          //We have to change the clientsize to make room for borders
          //if not, the border is limited in how thick it is.
          if (m.Msg == 0x83) //WM_NCCALCSIZE   
          {
            if (m.WParam == IntPtr.Zero)
            {
                RECT rect = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
                rect.left += clientPadding;
                rect.right -= clientPadding;
                rect.top += clientPadding;
                rect.bottom -= clientPadding;
                Marshal.StructureToPtr(rect, m.LParam, false);
            }
            else
            {
                NCCALSIZE_PARAMS rects = (NCCALSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(NCCALSIZE_PARAMS));
                rects.newWindow.left += clientPadding;
                rects.newWindow.right -= clientPadding;
                rects.newWindow.top += clientPadding;
                rects.newWindow.bottom -= clientPadding;
                Marshal.StructureToPtr(rects, m.LParam, false);
            }
          }
          if (m.Msg == 0x85) //WM_NCPAINT
          {                 
            IntPtr wDC = GetWindowDC(Handle);
            using(Graphics g = Graphics.FromHdc(wDC)){                                                
              Rectangle rect = new Rectangle(0,0,Width,Height);
              Rectangle inner = new Rectangle(0, 0, Width, Height);
              inner.Offset(actualBorderWidth + 2, actualBorderWidth + 2);
              inner.Width -= 2 * actualBorderWidth + 4;
              inner.Height -= 2 * actualBorderWidth + 4;
              Region r = new Region(rect);
              r.Xor(inner);
              using (System.Drawing.Drawing2D.HatchBrush brush = new System.Drawing.Drawing2D.HatchBrush(System.Drawing.Drawing2D.HatchStyle.SmallCheckerBoard, Color.Green, Color.Red))
              {                    
                g.FillRegion(brush, r);
              }
            }
            return;
          }
          base.WndProc(ref m);
      }
    }