title: GDI+ Drawing Rectangle Is Slow
body: <p>I've developed a Windows Forms Application to draw a rectangular region relevant to the user's mouse position as he or she clicks, holds and drags the mouse.</p>
  
  <p>The class is very simple and is as followed:</p>
  
  <pre><code>public partial class MainForm : LayeredForm
  {
      private bool drawing = false;
      private Point startLocation = Point.Empty;
  
      public MainForm()
      {
          InitializeComponent();
          Location = Screen.PrimaryScreen.Bounds.Location;
          Size = Screen.PrimaryScreen.Bounds.Size;
          Cursor = Cursors.Cross;
          TopMost = true;
          ShowInTaskbar = false;
          DoubleBuffered = true;
      }
  
      private void MainForm_MouseDown(object sender, MouseEventArgs e)
      {
          drawing = true;
          startLocation = e.Location;
      }
  
      private void MainForm_MouseMove(object sender, MouseEventArgs e)
      {
          if (drawing)
              Invalidate();
      }
  
      private void MainForm_MouseUp(object sender, MouseEventArgs e)
      {
          drawing = false;
      }
  
      private void MainForm_Paint(object sender, PaintEventArgs e)
      {
          Rectangle r = new Rectangle(Math.Min(startLocation.X, Cursor.Position.X), Math.Min(startLocation.Y, Cursor.Position.Y),
              Math.Abs(startLocation.X - Cursor.Position.X), Math.Abs(startLocation.Y - Cursor.Position.Y));
  
          e.Graphics.FillRectangle(Brushes.Blue, r);
      }
  }
  
  
  public class LayeredForm : Form
  {
      public new event PaintEventHandler Paint;
  
      public LayeredForm()
      {
          SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
          StartPosition = FormStartPosition.Manual;
      }
  
      protected override CreateParams CreateParams
      {
          get
          {
              if (DesignMode) return base.CreateParams;
              CreateParams cParams = base.CreateParams;
              cParams.ExStyle = cParams.ExStyle | 0x80000;
              return cParams;
          }
      }
  
      private void PaintNative(Bitmap bitmap)
      {
          IntPtr hdcDestination = Win32.GetDC(IntPtr.Zero);
          IntPtr hdcSource = Win32.CreateCompatibleDC(hdcDestination);
          IntPtr hdcBitmap = IntPtr.Zero;
          IntPtr previousBitmap = IntPtr.Zero;
  
          try
          {
              hdcBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
              previousBitmap = Win32.SelectObject(hdcSource, hdcBitmap);
  
              Win32.SIZE size = new Win32.SIZE(bitmap.Width, bitmap.Height);
              Win32.POINT source = new Win32.POINT(0, 0);
              Win32.POINT destination = new Win32.POINT(Left, Top);
              Win32.BLENDFUNCTION blendFunc = new Win32.BLENDFUNCTION()
              {
                  BlendOp = Win32.AC_SRC_OVER,
                  BlendFlags = 0,
                  SourceConstantAlpha = 50,
                  AlphaFormat = Win32.AC_SRC_ALPHA
              };
  
              Win32.UpdateLayeredWindow(Handle, hdcDestination, ref destination, ref size, hdcSource, ref source, 0, ref blendFunc, 2);
          }
          finally
          {
              Win32.ReleaseDC(IntPtr.Zero, hdcDestination);
              if (hdcBitmap != IntPtr.Zero)
              {
                  Win32.SelectObject(hdcSource, previousBitmap);
                  Win32.DeleteObject(hdcBitmap);
              }
              Win32.DeleteDC(hdcSource);
          }
      }
  
      public new void Invalidate()
      {
          using (Bitmap bitmap = new Bitmap(ClientSize.Width, ClientSize.Height))
          {
              using (Graphics graphics = Graphics.FromImage(bitmap))
              {
                  if (Paint != null)
                      Paint(this, new PaintEventArgs(graphics, Rectangle.Empty));
              }
              PaintNative(bitmap);
          }
      }
  }
  </code></pre>
  
  <p>On my computer and most others, everything runs fine. However, after concluding some testing on various machines I found that some computers where struggling to draw the rectangle (noticeably slow, and choppy). I think I have identified the issue however I am in need of validation and a resolution to this issue. </p>
  
  <p>I believe that the problem lies with the fact that every time the mouse move event is raised, the entire form is drawn again, and again. On weak computers with large resolutions, this is very strenuous.</p>
  
  <p>After conducting some research, I think that the solution is to only draw the part of the rectangle that's changed and not the entire form, although I'm clueless as to how to do this. I'd really appreciate any help that SO can offer, thanks in advance. </p>
  
  <h2>Update</h2>
  
  <p>Complete code for Ken:</p>
  
  <pre><code>public sealed partial class RegionForm : LayeredWindow // : Form
  {
      private Bitmap bitmap;
      private bool mouseDown;
      private Point newPoint = Point.Empty;
      private Point oldPoint = Point.Empty;
      private Point startPoint = Point.Empty;
  
      public RegionForm()
      {
          InitializeComponent();
          Location = Screen.PrimaryScreen.Bounds.Location;
          Size = Screen.PrimaryScreen.Bounds.Size;
          Cursor = Cursors.Cross;
          TopMost = true;
          ShowInTaskbar = false;
      }
  
      private void regionPanel_MouseDown(object sender, MouseEventArgs e)
      {
          bitmap = new Bitmap(regionPanel.ClientSize.Width,
                              regionPanel.ClientSize.Height,
                              PixelFormat.Format32bppPArgb);
  
          regionPanel.DrawToBitmap(bitmap, regionPanel.ClientRectangle);
          startPoint = e.Location;
          mouseDown = true;
      }
  
      private void regionPanel_MouseUp(object sender, MouseEventArgs e)
      {
          mouseDown = false;
  
          if (bitmap != null)
          {
              bitmap.Dispose();
              bitmap = null;
          }
  
          Rectangle region = new Rectangle(startPoint, new Size(oldPoint.X - startPoint.X + 1,
                                                                oldPoint.Y - startPoint.Y + 1));
          regionPanel.Invalidate(region, true);
      }
  
      private void regionPanel_MouseMove(object sender, MouseEventArgs e)
      {
          if (mouseDown)
          {
              using (Graphics g = regionPanel.CreateGraphics())
              {
                  g.SmoothingMode = SmoothingMode.None;
                  newPoint = e.Location;
                  ClearRegion(g);
                  oldPoint = newPoint;
                  DrawRegion(g);
              }
          }
      }
  
      private void DrawRegion(Graphics g)
      {
          int x1 = startPoint.X;
          int y1 = startPoint.Y;
          int x2 = newPoint.X;
          int y2 = newPoint.Y;
  
          //block "negative" selection
          if (x1 &gt; x2)
          {
              x2 = x1;
          }
          if (y1 &gt; y2)
          {
              y2 = y1;
          }
  
          //Draw a red rectangle
          g.FillRectangle(Brushes.Red, x1, y1, x2 - x1, y2 - y1);
      }
  
      private void ClearRegion(Graphics g)
      {
          int x1 = startPoint.X;
          int y1 = startPoint.Y;
          int x2 = oldPoint.X;
          int y2 = oldPoint.Y;
  
          if (x1 &gt; x2)
          {
              x2 = x1;
          }
          if (y1 &gt; y2)
          {
              y2 = y1;
          }
  
          //check left line
          if (newPoint.Y &lt; y2)
          {
              Rectangle rectdst = new Rectangle(x1, newPoint.Y, 1, oldPoint.Y - newPoint.Y);
              g.DrawImage(bitmap, rectdst, rectdst, GraphicsUnit.Pixel);
          }
  
          //upper line
          if (newPoint.X &lt; x2)
          {
              Rectangle rectdst = new Rectangle(newPoint.X, y1, oldPoint.X - newPoint.X, 1);
              g.DrawImage(bitmap, rectdst, rectdst, GraphicsUnit.Pixel);
          }
  
          //right line
          if (newPoint.X != x2 || newPoint.Y &lt; y2)
          {
              int h = 0;
              int y = 0;
              if (newPoint.X == x2)
              {
                  y = newPoint.Y;
                  h = oldPoint.Y - newPoint.Y + 1;
              }
              else
              {
                  y = startPoint.Y;
                  h = oldPoint.Y - startPoint.Y + 1;
              }
  
              Rectangle rectdst = new Rectangle(oldPoint.X, y, 1, h);
              g.DrawImage(bitmap, rectdst, rectdst, GraphicsUnit.Pixel);
          }
  
          //bottom line
          if (newPoint.Y != y2 || newPoint.X &lt; x2)
          {
              int w = 0;
              int x = 0;
  
              if (newPoint.Y == y2)
              {
                  x = newPoint.X;
                  w = oldPoint.X - newPoint.X + 1;
              }
              else
              {
                  x = startPoint.X;
                  w = oldPoint.X - x1 + 1;
              }
  
              Rectangle rectdst = new Rectangle(x, oldPoint.Y, w, 1);
              g.DrawImage(bitmap, rectdst, rectdst, GraphicsUnit.Pixel);
          }
      }
  
  public class LayeredWindow : Form
  {
      public new event PaintEventHandler Paint;
  
      public LayeredWindow()
      {
          SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
          StartPosition = FormStartPosition.Manual;
      }
  
      protected override CreateParams CreateParams
      {
          get
          {
              if (DesignMode) return base.CreateParams;
              CreateParams cParams = base.CreateParams;
              cParams.ExStyle = cParams.ExStyle | 0x80000;
              return cParams;
          }
      }
  
      private void PaintNative(Bitmap bitmap)
      {
          IntPtr hdcDestination = Win32.GetDC(IntPtr.Zero);
          IntPtr hdcSource = Win32.CreateCompatibleDC(hdcDestination);
          IntPtr hdcBitmap = IntPtr.Zero;
          IntPtr previousBitmap = IntPtr.Zero;
  
          try
          {
              hdcBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
              previousBitmap = Win32.SelectObject(hdcSource, hdcBitmap);
  
              Size size = new Size(bitmap.Width, bitmap.Height);
              Point source = new Point(0, 0);
              Point destination = new Point(Left, Top);
              Win32.BLENDFUNCTION blendFunc = new Win32.BLENDFUNCTION()
              {
                  BlendOp = Win32.AC_SRC_OVER,
                  BlendFlags = 0,
                  SourceConstantAlpha = 50,
                  AlphaFormat = Win32.AC_SRC_ALPHA
              };
  
              Win32.UpdateLayeredWindow(Handle, hdcDestination, ref destination, ref size, hdcSource, ref source, 0, ref blendFunc, 2);
          }
          finally
          {
              Win32.ReleaseDC(IntPtr.Zero, hdcDestination);
              if (hdcBitmap != IntPtr.Zero)
              {
                  Win32.SelectObject(hdcSource, previousBitmap);
                  Win32.DeleteObject(hdcBitmap);
              }
              Win32.DeleteDC(hdcSource);
          }
      }
  
      public new void Invalidate()
      {
          using (Bitmap bitmap = new Bitmap(ClientSize.Width, ClientSize.Height))
          {
              using (Graphics graphics = Graphics.FromImage(bitmap))
              {
                  if (Paint != null)
                      Paint(this, new PaintEventArgs(graphics, Rectangle.Empty));
              }
              PaintNative(bitmap);
          }
      }
  }
  
  public sealed class Win32
  {
      [DllImport("user32.dll")]
      public static extern bool HideCaret(IntPtr hWnd);
  
      [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
      public static extern short GetKeyState(int keyCode);
  
      [DllImport("user32.dll")]
      public static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
  
      [DllImport("user32.dll")]
      public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
  
      [DllImport("gdi32.dll", SetLastError = true)]
      public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
  
      [DllImport("user32.dll")]
      public static extern IntPtr GetDC(IntPtr hWnd);
  
      [DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
      public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
  
      [DllImport("user32.dll")]
      public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
  
      [DllImport("gdi32.dll")]
      public static extern bool DeleteDC(IntPtr hdc);
  
      [DllImport("gdi32.dll")]
      public static extern bool DeleteObject(IntPtr hObject);
  
      [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
      public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pptSrc, uint crKey, [In] ref BLENDFUNCTION pblend, uint dwFlags);
  
      [DllImport("user32.dll")]
      public static extern IntPtr GetDesktopWindow();
  
      [DllImport("user32.dll")]
      public static extern IntPtr GetWindowDC(IntPtr ptr);
  
      [DllImport("gdi32.dll")]
      public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
  
      [DllImport("gdi32.dll")]
      public static extern bool BitBlt(IntPtr hdcDest, int xDest, int yDest, int wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, CopyPixelOperation rop);
  
      [DllImport("user32.dll")]
      public static extern IntPtr GetForegroundWindow();
  
      [DllImport("user32.dll")]
      public static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);
  
      public const byte AC_SRC_OVER = 0;
      public const byte AC_SRC_ALPHA = 1;
      public const byte ULW_ALPHA = 2;
  
      [StructLayout(LayoutKind.Sequential, Pack = 1)]
      public struct BLENDFUNCTION
      {
          public byte BlendOp;
          public byte BlendFlags;
          public byte SourceConstantAlpha;
          public byte AlphaFormat;
      }
  
      [StructLayout(LayoutKind.Sequential)]
      public struct RECT
      {
          public int Left;
          public int Top;
          public int Right;
          public int Bottom;
      }
  
  }
  </code></pre>
  
  <p>Solution Download: <a href="http://www.mediafire.com/?b9ql4pzh69u10n4" rel="nofollow">http://www.mediafire.com/?b9ql4pzh69u10n4</a></p>