In two previous posts (here and here) I have previously posted about how to draw rubber band selection rectangles similar to what Explorer does. Now a reader contacted me by email and asked for an extension: he wants to have a reverse selection, similar to this image:

rubberband-request.jpg

No problem, of course :-)

I started out from the improved version of the first demo and made a few changes — all you have to do is replace the SelectionPanel.OnPaint method with this:

protected override void OnPaint(PaintEventArgs e) {
  ColorMatrix colorMatrix = new ColorMatrix(new float[][] {
    new float[] {1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
    new float[] {0.0f, 1.0f, 0.0f, 0.0f, 0.0f},
    new float[] {0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
    new float[] {0.0f, 0.0f, 0.0f, 0.3f, 0.0f},
    new float[] {0.0f, 0.0f, 0.0f, 0.0f, 1.0f}
  });

  ImageAttributes imageAttributes = new ImageAttributes( );
  imageAttributes.SetColorMatrix(
    colorMatrix,
    ColorMatrixFlag.Default,
    ColorAdjustType.Bitmap);
  Point[] destPoints = new Point[] {
    new Point(ClientRectangle.Left, ClientRectangle.Top),
    new Point(ClientRectangle.Right, ClientRectangle.Top),
    new Point(ClientRectangle.Left, ClientRectangle.Bottom)
  };
  e.Graphics.DrawImage(backgroundBitmap, destPoints,
    usableRect, GraphicsUnit.Pixel, imageAttributes);

  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));

    Point srcRectLocation = selectedRect.Location;
    srcRectLocation.Offset(usableRect.Location);
    Rectangle srcRect = new Rectangle(srcRectLocation,
      selectedRect.Size);
    e.Graphics.DrawImage(backgroundBitmap, selectedRect,
      srcRect, GraphicsUnit.Pixel);

    using (Pen pen = new Pen(Color.Black)) {
      pen.DashPattern = new float[] { 2f, 2f };
      int thirdOfHeight = selectedRect.Height / 3;
      int thirdOfWidth = selectedRect.Width / 3;
      e.Graphics.DrawRectangle(Pens.White, selectedRect);
      e.Graphics.DrawLine(Pens.White,
        selectedRect.Left,
        selectedRect.Top + thirdOfHeight,
        selectedRect.Right,
        selectedRect.Top + thirdOfHeight);
      e.Graphics.DrawLine(Pens.White,
        selectedRect.Left,
        selectedRect.Bottom - thirdOfHeight,
        selectedRect.Right,
        selectedRect.Bottom - thirdOfHeight);
      e.Graphics.DrawLine(Pens.White,
        selectedRect.Left + thirdOfWidth,
        selectedRect.Top,
        selectedRect.Left + thirdOfWidth,
        selectedRect.Bottom);
      e.Graphics.DrawLine(Pens.White,
        selectedRect.Right - thirdOfWidth,
        selectedRect.Top,
        selectedRect.Right - thirdOfWidth,
        selectedRect.Bottom);
      e.Graphics.DrawRectangle(pen, selectedRect);
      e.Graphics.DrawLine(pen,
        selectedRect.Left,
        selectedRect.Top + thirdOfHeight,
        selectedRect.Right,
        selectedRect.Top + thirdOfHeight);
      e.Graphics.DrawLine(pen,
        selectedRect.Left,
        selectedRect.Bottom - thirdOfHeight,
        selectedRect.Right,
        selectedRect.Bottom - thirdOfHeight);
      e.Graphics.DrawLine(pen,
        selectedRect.Left + thirdOfWidth,
        selectedRect.Top,
        selectedRect.Left + thirdOfWidth,
        selectedRect.Bottom);
      e.Graphics.DrawLine(pen,
        selectedRect.Right - thirdOfWidth,
        selectedRect.Top,
        selectedRect.Right - thirdOfWidth,
        selectedRect.Bottom);
    }
  }
}

The result is this (I got rid of my main form drawing routine and inserted a nice background picture instead). Very nice!

rubberband_2ddemo_2d3.png

Update: As requested, I’m making the complete sample project available. Here’s the download.