Search code examples
c#graphicsdatagridviewpaintclipping

Displaying a rotated string - DataGridView.RowPostPaint


I want to display a lengthy rotated string in the background of one of my rows in a DataGridView. However, this:

private void dataGridView1_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
{
    if (e.RowIndex == 0)
    {
        ...
        //Draw the string
        Graphics g = dataGridView1.CreateGraphics();
        g.Clip = new Region(e.RowBounds);
        g.RotateTransform(-45);
        g.DrawString(printMe, font, brush, e.RowBounds, format);
    }
}

does not work because text is clipped before it's rotated.

I've also tried painting on a Bitmap first, but there seems to be a problem painting transparent Bitmaps - the text comes out pure black.

Any ideas?


Solution

  • I figured it out. The problem was that Bitmaps apparently don't have transparency, even when you use PixelFormat.Format32bppArgb. Drawing the string caused it to draw over a black background, which is why it was so dark.

    The solution was to copy the row from the screen onto a bitmap, draw onto the bitmap, and copy that back to the screen.

    g.CopyFromScreen(absolutePosition, Point.Empty, args.RowBounds.Size);
    
    //Draw the rotated string here
    
    args.Graphics.DrawImageUnscaledAndClipped(buffer, args.RowBounds);
    

    Here is the full code listing for reference:

    private void dataGridView1_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs args)
    {
        if(args.RowIndex == 0)
        {
            Font font = new Font("Verdana", 11);
            Brush brush = new SolidBrush(Color.FromArgb(70, Color.DarkGreen));
            StringFormat format = new StringFormat
            {
                FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.NoClip,
                Trimming = StringTrimming.None,
            };
    
            //Setup the string to be printed
            string printMe = String.Join(" ", Enumerable.Repeat("RUNNING", 10).ToArray());
            printMe = String.Join(Environment.NewLine, Enumerable.Repeat(printMe, 50).ToArray());
    
            //Draw string onto a bitmap
            Bitmap buffer = new Bitmap(args.RowBounds.Width, args.RowBounds.Height);
            Graphics g = Graphics.FromImage(buffer);
            Point absolutePosition = dataGridView1.PointToScreen(args.RowBounds.Location);
            g.CopyFromScreen(absolutePosition, Point.Empty, args.RowBounds.Size);
            g.RotateTransform(-45, MatrixOrder.Append);
            g.TranslateTransform(-50, 0, MatrixOrder.Append); //So we don't see the corner of the rotated rectangle
            g.DrawString(printMe, font, brush, args.RowBounds, format);
    
            //Draw the bitmap onto the table
            args.Graphics.DrawImageUnscaledAndClipped(buffer, args.RowBounds);
        }
    }