Drawing a Selection Rubber Band Like Explorer

I saw the question coming up in a newsgroup today: how do you draw a selection rubber band just like the one Explorer uses, in C#? The first thing that came to mind was the ControlPaint.DrawReversibleFrame() method, but that’s rather restricted. It’s fine to draw a rectangle around an area to select, but it can’t do anything more than that and it also has problems because it draws over windows that are supposed to be in front of the current app window. Here are screenshots of a selection made in Explorer and a selection made in my sample program. Nice, huh? 😃

So, here’s the code. I created this in VS 2005 beta 2, but I don’t think I used any .NET 2 specific things – if you find any, let me know. To use the sample, just create a new project and replace your newly created Form1 mainform by this code (and throw away the .Designer.cs and resource files).

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace SelectionRectTest {
  public class Form1 : Form {
    public Form1( ) {
      DoubleBuffered = true;
      BackColor = Color.White;

      selectionColor = Color.FromArgb(200, 0xE8, 0xED, 0xF5);
      selectionBrush = new SolidBrush(selectionColor);
      frameColor =  Color.FromArgb(0x33, 0x5E, 0xA8);
      framePen = new Pen(frameColor);
    }

    Color selectionColor;
    Brush selectionBrush;
    Color frameColor;
    Pen framePen;

    protected override void OnPaint(PaintEventArgs e) {
      e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

      // Draw some stuff so the transparent selection becomes visible
      int height = ClientRectangle.Height;
      int heightTenth = height / 10;
      int width = ClientRectangle.Width;
      int widthTenth = width / 10;

      e.Graphics.DrawLines(Pens.Red, new Point[] {
        new Point(widthTenth, heightTenth * 3),
        new Point(widthTenth * 5, heightTenth),
        new Point(widthTenth * 8, heightTenth * 9),
        new Point(widthTenth, heightTenth * 3)
      });
      e.Graphics.DrawEllipse(Pens.Blue,
        widthTenth * 4,
        heightTenth * 3,
        widthTenth * 5,
        heightTenth * 4);

      // Now, if needed, draw the selection rectangle
      if (mouseDownPos != Point.Empty) {
        Point mousePos = PointToClient(MousePosition);
        Rectangle selectedRect = new Rectangle(
          Math.Min(mouseDownPos.X, mousePos.X),
          Math.Min(mouseDownPos.Y, mousePos.Y),
          Math.Abs(mousePos.X - mouseDownPos.X),
          Math.Abs(mousePos.Y - mouseDownPos.Y));
        e.Graphics.FillRectangle(selectionBrush, selectedRect);
        e.Graphics.DrawRectangle(framePen, selectedRect);
      }
    }

    protected override void OnResize(EventArgs e) {
      base.OnResize(e);
      Invalidate( );
    }

    Point mouseDownPos = Point.Empty;

    protected override void OnMouseDown(MouseEventArgs e) {
      base.OnMouseDown(e);

      if (e.Button == MouseButtons.Left)
        mouseDownPos = e.Location;
    }

    protected override void OnMouseMove(MouseEventArgs e) {
      base.OnMouseMove(e);
      if (e.Button == MouseButtons.Left &&
        mouseDownPos != Point.Empty)
        Invalidate( );
    }

    protected override void OnMouseUp(MouseEventArgs e) {
      base.OnMouseUp(e);
      mouseDownPos = Point.Empty;
      Invalidate( );
    }
  }
}

Sorry, this blog does not support comments.

I used various blog hosting services since this blog was established in 2005, but unfortunately they turned out to be unreliable in the long term and comment threads were lost in unavoidable transitions. At this time I don't want to enable third-party services for comments since it has become obvious in recent years that these providers invariably monetize information about their visitors and users.

Please use the links in the page footer to get in touch with me. I'm available for conversations on Keybase, Matrix, Mastodon or Twitter, as well as via email.