c# – 如何在.Net WinForms控件上绘制自定义边框

前端之家收集整理的这篇文章主要介绍了c# – 如何在.Net WinForms控件上绘制自定义边框前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我一直在尝试为现有的.Net WinForms控件绘制自定义边框.我试过这个是通过创建一个类来控制我想要改变它的边框颜色,然后在绘画过程中尝试几个东西.我尝试过以下方法

1.捕获WM_NCPAINT.这有点起作用.下面的代码的问题是,当控件调整大小时,边框将在右侧和底侧被切断.不好.

  1. protected override void WndProc(ref Message m)
  2. {
  3. if (m.Msg == NativeMethods.WM_NCPAINT) {
  4. WmNcPaint(ref m);
  5. return;
  6. }
  7. base.WndProc(ref m);
  8. }
  9.  
  10. private void WmNcPaint(ref Message m)
  11. {
  12. if (BorderStyle == BorderStyle.None) {
  13. return;
  14. }
  15.  
  16. IntPtr hDC = NativeMethods.GetWindowDC(m.HWnd);
  17. if (hDC != IntPtr.Zero) {
  18. using (Graphics g = Graphics.FromHdc(hDC)) {
  19. ControlPaint.DrawBorder(g,new Rectangle(0,this.Width,this.Height),_BorderColor,ButtonBorderStyle.Solid);
  20. }
  21. m.Result = (IntPtr)1;
  22. NativeMethods.ReleaseDC(m.HWnd,hDC);
  23. }
  24. }

2.覆盖void OnPaint.这适用于某些控件,但不是全部.这还要求您将BorderStyle设置为BorderStyle.None,并且您必须手动清除paint上的背景,否则调整大小时的you get this.

  1. protected override void OnPaint(PaintEventArgs e)
  2. {
  3. base.OnPaint(e);
  4. ControlPaint.DrawBorder(e.Graphics,ButtonBorderStyle.Solid);
  5. }

3.重写void OnResize和void OnPaint(如方法2中所示).通过这种方式,它可以很好地调整大小,但是当Panel启用了AutoScroll时则不会,在这种情况下,当向下滚动时它将是look like this.如果我尝试使用WM_NCPAINT绘制边框,则Refresh()无效.

  1. protected override void OnResize(EventArgs eventargs)
  2. {
  3. base.OnResize(eventargs);
  4. Refresh();
  5. }

建议非常欢迎.我想知道最好的方法是什么,对于多种类型的控件(我必须为多个默认的WinForms控件执行此操作).

解决方法

编辑:所以我想出了导致我最初问题的原因.经过很长一段时间的修补,试验和查看.Net框架源代码,这里有一个明确的方法(考虑到你有一个控件继承自你想要绘制自定义边框的控件):
  1. [DllImport("user32.dll")]
  2. public static extern bool RedrawWindow(IntPtr hWnd,IntPtr lprcUpdate,IntPtr hrgnUpdate,RedrawWindowFlags flags);
  3.  
  4. [Flags()]
  5. public enum RedrawWindowFlags : uint
  6. {
  7. Invalidate = 0X1,InternalPaint = 0X2,Erase = 0X4,Validate = 0X8,NoInternalPaint = 0X10,NoErase = 0X20,NoChildren = 0X40,AllChildren = 0X80,UpdateNow = 0X100,EraseNow = 0X200,Frame = 0X400,NoFrame = 0X800
  8. }
  9.  
  10. // Make sure that WS_BORDER is a style,otherwise borders aren't painted at all
  11. protected override CreateParams CreateParams
  12. {
  13. get
  14. {
  15. if (DesignMode) {
  16. return base.CreateParams;
  17. }
  18. CreateParams cp = base.CreateParams;
  19. cp.ExStyle &= (~0x00000200); // WS_EX_CLIENTEDGE
  20. cp.Style |= 0x00800000; // WS_BORDER
  21. return cp;
  22. }
  23. }
  24.  
  25. // During OnResize,call RedrawWindow with Frame|UpdateNow|Invalidate so that the frame is always redrawn accordingly
  26. protected override void OnResize(EventArgs e)
  27. {
  28. base.OnResize(e);
  29. if (DesignMode) {
  30. RecreateHandle();
  31. }
  32. RedrawWindow(this.Handle,IntPtr.Zero,RedrawWindowFlags.Frame | RedrawWindowFlags.UpdateNow | RedrawWindowFlags.Invalidate);
  33. }
  34.  
  35. // Catch WM_NCPAINT for painting
  36. protected override void WndProc(ref Message m)
  37. {
  38. if (m.Msg == NativeMethods.WM_NCPAINT) {
  39. WmNcPaint(ref m);
  40. return;
  41. }
  42. base.WndProc(ref m);
  43. }
  44.  
  45. // Paint the custom frame here
  46. private void WmNcPaint(ref Message m)
  47. {
  48. if (BorderStyle == BorderStyle.None) {
  49. return;
  50. }
  51.  
  52. IntPtr hDC = NativeMethods.GetWindowDC(m.HWnd);
  53. using (Graphics g = Graphics.FromHdc(hDC)) {
  54. g.DrawRectangle(new Pen(_BorderColor),this.Width - 1,this.Height - 1));
  55. }
  56. NativeMethods.ReleaseDC(m.HWnd,hDC);
  57. }

简而言之,保持OnPaint不变,确保设置了WS_BORDER,然后捕获WM_NCPAINT并通过hDC绘制边框,并确保在OnResize中调用RedrawWindow.

这甚至可以扩展以绘制自定义滚动条,因为这是在WM_NCPAINT期间可以绘制的窗口框架的一部分.

我从中删除了我的旧答案.

编辑2:对于ComboBox,你必须在WndProc()中捕获WM_PAINT,因为由于某种原因,用于绘制ComboBox的.Net源不使用OnPaint(),而是使用WM_PAINT.所以像这样:

  1. protected override void WndProc(ref Message m)
  2. {
  3. base.WndProc(ref m);
  4.  
  5. if (m.Msg == NativeMethods.WM_PAINT) {
  6. OnWmPaint();
  7. }
  8. }
  9.  
  10. private void OnWmPaint()
  11. {
  12. using (Graphics g = CreateGraphics()) {
  13. if (!_HasBorders) {
  14. g.DrawRectangle(new Pen(BackColor),this.Height - 1));
  15. return;
  16. }
  17. if (!Enabled) {
  18. g.DrawRectangle(new Pen(_BorderColorDisabled),this.Height - 1));
  19. return;
  20. }
  21. if (ContainsFocus) {
  22. g.DrawRectangle(new Pen(_BorderColorActive),this.Height - 1));
  23. return;
  24. }
  25. g.DrawRectangle(new Pen(_BorderColor),this.Height - 1));
  26. }
  27. }

猜你在找的C#相关文章