2

I have a form with three panels. The top panel contains listboxes, the middle panel contains a grid and the bottom panel contains a grid. I need to take a screenshot of the bottom grid but sometimes there are more rows in the grid and you need to scroll to see every row. I want to make the bottom grid the size of the form before I take the screenshot and can do this by setting .Visible to false for the two top panels. My problem is that the screenshot is taken before the form has redrawn itself to show the grid as the size of the form. How can I guarantee that the form has redrawn/repainted before I execute the code to take the screenshot?

I'm using the answer of ArsenMkrt from Capture screenshot of active window? to take the screenshot.

EDIT: The grid is an Infragistics UltraGrid.

Community
  • 1
  • 1
Ryan Rodemoyer
  • 5,548
  • 12
  • 44
  • 54

3 Answers3

3

Call the form's Update() method. If there are any pending paints then you can be sure they'll be performed and the form is fully drawn. Definitely the case here, hiding the panels requires the form to redraw its background.

This only works for your own form, not for a window owned by another process. Using the form's DrawToBitmap() method usually works too (no synchronization required), but not all child controls support it. Notably RichTextBox and WebBrowser as well as many other ActiveX controls don't implement the underlying Windows message correctly.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
1

If you are using the Winforms DataGrid, you shouldn't need to go through all that trouble. Just use Control.DrawToBitmap()

var width = dataGridView1.Width;
var height = dataGridView1.Height;
var x = dataGridView1.Left;
var y = dataGridView1.Top;

var bitmap = new Bitmap(width, height);
var targetBounds = new Rectangle(x, y, width, height);
dataGridView1.DrawToBitmap(bitmap, targetBounds);

bitmap.Save("C:\\DataGridView.bmp");
bopapa_1979
  • 8,949
  • 10
  • 51
  • 76
  • You might also try Control.Refresh()... dataGridView1.Refresh(), which forces an immediate repaint of the control and all its children. I'm not sure if this is thread-safe or not. – bopapa_1979 Jan 19 '12 at 00:42
0

Use Applicaton.DoEvents() to allow all the windows messages to be processed and so the resize and painting will be completed on return from the call. Immediately afterward you can then take your screenshot of the Form.

Ken White
  • 123,280
  • 14
  • 225
  • 444
Phil Wright
  • 22,580
  • 14
  • 83
  • 137
  • `DoEvents` should be **absolutely** the last thing you consider. First, because it's `VB.NET` and not `C#`, so it's not available. Second, because in VB/VB.NET it causes problems due to reentrancy. Third, there is a better way to do it 99.999999999999999% of the time, and having to resort to using it means you're doing something wrong. – Ken White Jan 19 '12 at 00:32
  • Application.DoEvents() has nothing to do with the language. It is available from all .NET languages. – Phil Wright Jan 19 '12 at 00:37
  • OK. Thanks - I wasn't aware of C# having that flaw as well. Drop the first objection, and remove the `in VB/VB.NET` reference in the second. The rest still stands. :) I'll remove the downvote, though, because it was probably hasty based on that correction. I can't upvote it, though, because of the other two reasons. – Ken White Jan 19 '12 at 01:06
  • Your right, it certainly has its risks with re-entrancy and didn't realise there was a DrawToBitmap available on the DataGridView. – Phil Wright Jan 19 '12 at 02:48