How to Paint an Image into a Row Your Own Way Without Using an Icon

Once again I spent a few hours trying out different things, so I would like to share with you an approach that works for me. As always, it is so simple once you know how to do it, but more practical than my words will certainly be these few lines of code:

First we need to create the cell:

C#
class DataGridViewFavoriteCell : DataGridViewImageCell
{
    public DataGridViewFavoriteCell()
    {
        //-Set the default type that the GetFormattedValue method will return
        ValueType = typeof(Bitmap);
    }
    protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, System.ComponentModel.TypeConverter valueTypeConverter, System.ComponentModel.TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context)
    {
        //-Return the default image, which I can then use in the Paint method
        return Bitmaps.ci.FavoritePng;
    }
    protected override void Paint(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
    {
        Image imgFavorites = null;
        Point locFavorites = Point.Empty;
        //-My own method that calculates the coordinates to paint at, calculates the image size and also shrinks the image to the required size. If there are many rows, it is a good idea to make the row width and height fixed, load the image only once and then just calculate its coordinates
        Listing.CalculatePoint(cellBounds, Bitmaps.ci.FavoritePng, ImageFormats.Png, out locFavorites, out imgFavorites);
        //-Paint the image itself. The background has to be painted first, otherwise whatever the application has underneath is used
        graphics.FillRectangle(Brushes.White, cellBounds);
        graphics.DrawImage(imgFavorites, locFavorites);
        Debug.Print(locFavorites.ToString());
        //-Paint the row borders
        base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
    }
}

Then the column:

C#
class DataGridViewFavoriteColumn : DataGridViewImageColumn
{
    public DataGridViewFavoriteColumn()
    {
        this.CellTemplate = new DataGridViewFavoriteCell();
        this.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
        this.ValueType = typeof(Bitmap);
    }
}

Which we finally put into the DataGridView:

C#
dataGridView1.Columns.RemoveAt(0);
//-I also tried doing it this way, with both true and false, but had no luck
dataGridView1.Columns.Insert(0, new DataGridViewFavoriteColumn());

So the final result can look like this. In other events (for example OnCellClick) you just cast to the type of your own cell, set, say, the opposite flag and trigger a repaint. That gives you an interactive cell with an image:

Custom painted cell

Categories

Leave a Reply