About Me

My photo
I'm a C# developer and that takes up most of my time but when I'm not in front of the computer, I do a lot of mountain biking, skiing and spending time with my dog. When I'm not doing any of that stuff, I'm spending time with my lovely wife.

Thursday, September 18, 2008

Transparent Datagridview

The datagridview. I don't like it and it doesn't like me. Today I was trying to get an image to show up behind a datagridview and it was simply not cooperating. The datagridview hates to be transparent for some reason.

Like everything else in my program, I decided to create a custom control. Here's the end result of my labour.



The purpose of this datagridview is to set and show various named locations on a floor plan. Users can select a named location from a combobox and the physical location that it represents will show up on the grid. If the user would like to change that location, they can click on another cell in the datagridview.

To avoid flicker, the style of the control was set to OptimizedDoubleBuffer like this:
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

To get the background image, I simply created an image property for the grid and set that at design time.
Once that was set, I ovverrode the PaintBackGround method and drew the image to the size of the datagridview. I'm not allowing the user to resize the grid so I won't have to worry about that.

protected override void PaintBackground(Graphics graphics,
Rectangle clipBounds, Rectangle gridBounds)
{
     base.PaintBackground(graphics, clipBounds, gridBounds);
     graphics.DrawImage(img, new Point(this.RowHeadersWidth,
        this.ColumnHeadersHeight));
}

I then had to override onMouseClick. Inside that method, if the current cell's background was set to transparent, the Style.BackColor and Style.SelectionBackColor of the current cell would be red, and if the background was red, the Style.BackColor and Style.SelectionBackColor would be set to transparent.

To get the background image to show through the cells, the onCellPainting event had to be overridden. In that event, I painted the background to whatever the current cellstyle is set to.
protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
{
     base.OnCellPainting(e);
     if (e.ColumnIndex > -1 && e.RowIndex > -1)
     {
        if (this[e.ColumnIndex, e.RowIndex].Style.BackColor 
           != Color.Red)
        {
           this[e.ColumnIndex, e.RowIndex].Style.BackColor = 
              Color.Transparent;
        }
        else
        {
           this[e.ColumnIndex, e.RowIndex].Style.BackColor = 
              Color.Red;
        }
     }
}
So there you have it. A lovely transparent DataGridView for all.

Here's the entire code. I apologize if it's difficult to read, but formatting code in this blog is very difficult.
using System.Linq;
using System.Windows.Forms;
using System.Drawing;

namespace testproject
public class imagedgv : DataGridView
{
     Image img;
     public Image Img
     {
        get { return img; }
        set {img = value; }
     }
     
     public imagedgv(): base()
     {
        SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
     }
     
     protected override void OnSizeChanged(EventArgs e)
     {
        base.OnSizeChanged(e);
        img = new Bitmap(img, this.Width - this.RowHeadersWidth , this.Height -                                                                                                
           this.ColumnHeadersHeight);
     }
     
     protected override void PaintBackground(Graphics graphics, Rectangle clipBounds, Rectangle      
      gridBounds)
     {
        base.PaintBackground(graphics, clipBounds, gridBounds);
        graphics.DrawImage(img, new Point(this.RowHeadersWidth, this.ColumnHeadersHeight));
     }
     
     protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
     {
        base.OnCellPainting(e);
        if (e.ColumnIndex > -1 && e.RowIndex > -1)
        {
           if (this[e.ColumnIndex, e.RowIndex].Style.BackColor != Color.Red)
              this[e.ColumnIndex, e.RowIndex].Style.BackColor = Color.Transparent;
           else
              this[e.ColumnIndex, e.RowIndex].Style.BackColor = Color.Red;
        }
     }
   
     protected override void OnMouseClick(MouseEventArgs e)
     {
        DataGridView.HitTestInfo hti = this.HitTest(e.X, e.Y);
        if (hti.Type == DataGridViewHitTestType.Cell)
        {
           DataGridViewCell c = this[hti.ColumnIndex, hti.RowIndex];
           if (c.Style.BackColor == Color.Red)
           {
              c.Style.BackColor = Color.Transparent;
              c.Style.SelectionBackColor = Color.Transparent;
           }
           else
           {
              c.Style.BackColor = Color.Red;
              c.Style.SelectionBackColor = Color.Red;
           }
        }
        base.OnMouseClick(e);
     }
}
Enjoy!

1 comment:

Adam Mendoza said...

I tried it but the image was blurry.