Advertisement
Guest User

RichTextBox with a custom border

a guest
Sep 21st, 2013
339
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.78 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Drawing;
  5. using System.Linq;
  6. using System.Runtime.InteropServices;
  7. using System.Text;
  8. using System.Windows.Forms;
  9.  
  10. namespace WindowsFormsApplication1
  11. {
  12.     public class RichTextBoxEx : RichTextBox
  13.     {
  14.  
  15.         private int _borderWidth = 1;
  16.         private Color _borderColor = Color.Black;
  17.  
  18.         public RichTextBoxEx() {  }
  19.  
  20.         [Category("Border")]
  21.         public int BorderWidth
  22.         {
  23.             get {
  24.                 return _borderWidth;
  25.             }
  26.             set {
  27.                 if (_borderWidth < 0)
  28.                     throw new ArgumentException("Border width must be non-negative", "BorderWidth");
  29.                 _borderWidth = value;
  30.                 Invalidate();
  31.                 InvalidateNC();
  32.             }
  33.            
  34.         }
  35.  
  36.         [Category("Border")]
  37.         public Color BorderColor
  38.         {
  39.             get
  40.             {
  41.                 return _borderColor;
  42.             }
  43.             set
  44.             {
  45.                 _borderColor = value;
  46.                 Invalidate();
  47.                 InvalidateNC();
  48.             }
  49.  
  50.         }
  51.  
  52.         protected override CreateParams CreateParams
  53.         {
  54.             get
  55.             {
  56.                 var cp = base.CreateParams;
  57.                 cp.ExStyle &= ~0x200; // WS_EX_CLIENTEDGE
  58.                 cp.Style &= ~0x00800000; // WS_BORDER
  59.                 return cp;
  60.             }
  61.         }
  62.        
  63.         protected override void WndProc(ref Message m)
  64.         {
  65.             switch (m.Msg)
  66.             {
  67.                 case (int)NativeMethods.WM_NCCALCSIZE:
  68.                     if (m.WParam == IntPtr.Zero || m.WParam == new IntPtr(1))
  69.                         RecalcNonClientArea(m.LParam);
  70.                     break;
  71.                 case (int)NativeMethods.WM_NCPAINT:
  72.                     OnWMNCPaint(ref m);
  73.                     break;
  74.                 case (int)NativeMethods.WM_NCHITTEST:
  75.                     m.Result = PerformHitTest(new Point(m.LParam.ToInt32()));
  76.                     return;
  77.             }
  78.  
  79.             base.WndProc(ref m);
  80.         }
  81.  
  82.         protected override void OnResize(EventArgs eventargs)
  83.         {
  84.             InvalidateNC();
  85.             base.OnResize(eventargs);
  86.         }
  87.  
  88.         private void OnWMNCPaint(ref Message m)
  89.         {
  90.             var hDC = NativeMethods.GetWindowDC(m.HWnd);
  91.             if (hDC == IntPtr.Zero) return;
  92.  
  93.             var hrgnWindow = IntPtr.Zero;
  94.             var hrgnClient = IntPtr.Zero;
  95.  
  96.             try
  97.             {
  98.                 var rect = new Rectangle(_borderWidth, _borderWidth, Width - (_borderWidth * 2), Height - (_borderWidth * 2));
  99.                 hrgnWindow = NativeMethods.CreateRectRgn(0, 0, Width, Height);
  100.                 hrgnClient = NativeMethods.CreateRectRgn(rect.Left, rect.Top, rect.Right, rect.Bottom);
  101.  
  102.                 NativeMethods.CombineRgn(hrgnWindow, hrgnWindow, hrgnClient, 4); // RGN_DIFF
  103.                 NativeMethods.SelectClipRgn(hDC, hrgnWindow);
  104.  
  105.                 using (Graphics g = Graphics.FromHdc(hDC))
  106.                     g.Clear(BorderColor);
  107.  
  108.                 m.Result = IntPtr.Zero;
  109.             }
  110.             finally
  111.             {
  112.                 NativeMethods.ReleaseDC(m.HWnd, hDC);
  113.  
  114.                 if (hrgnWindow != IntPtr.Zero)
  115.                     NativeMethods.DeleteObject(hrgnWindow);
  116.  
  117.                 if (hrgnClient != IntPtr.Zero)
  118.                     NativeMethods.DeleteObject(hrgnClient);
  119.             }
  120.  
  121.         }
  122.  
  123.         private void InvalidateNC()
  124.         {
  125.             NativeMethods.SetWindowPos(this.Handle, IntPtr.Zero, 0, 0, 0, 0,
  126.                                  NativeMethods.SWP_NOMOVE |
  127.                                  NativeMethods.SWP_NOSIZE |
  128.                                  NativeMethods.SWP_NOZORDER |
  129.                                  NativeMethods.SWP_NOACTIVATE |
  130.                                  NativeMethods.SWP_DRAWFRAME);
  131.         }
  132.  
  133.         private void RecalcNonClientArea(IntPtr lParam)
  134.         {
  135.             NativeMethods.NCCALCSIZE_PARAMS csp;
  136.  
  137.             csp = (NativeMethods.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(
  138.                 lParam,
  139.                 typeof(NativeMethods.NCCALCSIZE_PARAMS));
  140.  
  141.             csp.rcNewWindow.Top += _borderWidth;
  142.             csp.rcNewWindow.Bottom -= _borderWidth;
  143.             csp.rcNewWindow.Left += _borderWidth;
  144.             csp.rcNewWindow.Right -= _borderWidth;
  145.  
  146.             Marshal.StructureToPtr(csp, lParam, false);
  147.         }
  148.  
  149.         private IntPtr PerformHitTest(Point screenPos)
  150.         {
  151.             Point windowPos = this.Parent.PointToClient(screenPos);
  152.             windowPos.Offset(-this.Location.X, -this.Location.Y);
  153.  
  154.             var clientWindowRect = new Rectangle(_borderWidth, _borderWidth, Width, Height);
  155.  
  156.             return clientWindowRect.Contains(windowPos) ? (IntPtr)NativeMethods.HTCLIENT : (IntPtr)NativeMethods.HTBORDER;
  157.         }
  158.  
  159.  
  160.     }
  161.  
  162.     public class NativeMethods
  163.     {
  164.  
  165.         public const int WM_NCCALCSIZE = 0x83;
  166.         public const int WM_NCHITTEST = 0x84;
  167.         public const int WM_NCPAINT = 0x85;
  168.  
  169.         public const int SWP_NOSIZE = 0x0001;
  170.         public const int SWP_NOMOVE = 0x0002;
  171.         public const int SWP_NOZORDER = 0x0004;
  172.         public const int SWP_NOREDRAW = 0x0008;
  173.         public const int SWP_NOACTIVATE = 0x0010;
  174.         public const int SWP_FRAMECHANGED = 0x0020;
  175.         public const int SWP_DRAWFRAME = SWP_FRAMECHANGED;
  176.  
  177.         public const int HTCLIENT = 1;
  178.         public const int HTBORDER = 18;
  179.  
  180.         [DllImport("user32.dll")]
  181.         public static extern IntPtr GetWindowDC(IntPtr hWnd);
  182.  
  183.         [DllImport("user32.dll")]
  184.         [return: MarshalAs(UnmanagedType.Bool)]
  185.         public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
  186.  
  187.         [DllImport("user32.dll")]
  188.         public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
  189.  
  190.         [DllImport("gdi32.dll")]
  191.         public static extern bool DeleteObject(IntPtr hObject);
  192.  
  193.         [DllImport("gdi32.dll")]
  194.         public static extern IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
  195.  
  196.         [DllImport("gdi32.dll")]
  197.         public static extern int CombineRgn(IntPtr hrgnDest, IntPtr hrgnSrc1,
  198.            IntPtr hrgnSrc2, int fnCombineMode);
  199.  
  200.         [DllImport("gdi32.dll")]
  201.         public static extern int SelectClipRgn(IntPtr hdc, IntPtr hrgn);
  202.  
  203.         public struct RECT { public int Left, Top, Right, Bottom; }
  204.         public struct NCCALCSIZE_PARAMS
  205.         {
  206.             public RECT rcNewWindow;
  207.             public RECT rcOldWindow;
  208.             public RECT rcClient;
  209.             IntPtr lppos;
  210.         }
  211.  
  212.     }
  213. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement