1
using System;
2
using System.Text;
3
using System.Collections;
4
using System.Collections.Generic;
5
using System.Drawing;
6
using System.Drawing.Printing;
7
using System.Data;
8
using System.Windows.Forms;
9
10
class DataGridViewPrinter
11
{
12
private DataGridView TheDataGridView; // The DataGridView Control which will be printed
13
private PrintDocument ThePrintDocument; // The PrintDocument to be used for printing
14
private bool IsCenterOnPage; // Determine if the report will be printed in the Top-Center of the page
15
private bool IsWithTitle; // Determine if the page contain title text
16
private string TheTitleText; // The title text to be printed in each page (if IsWithTitle is set to true)
17
private Font TheTitleFont; // The font to be used with the title text (if IsWithTitle is set to true)
18
private Color TheTitleColor; // The color to be used with the title text (if IsWithTitle is set to true)
19
private bool IsWithPaging; // Determine if paging is used
20
21
static int CurrentRow; // A static parameter that keep track on which Row (in the DataGridView control) that should be printed
22
23
static int PageNumber;
24
25
private int PageWidth;
26
private int PageHeight;
27
private int LeftMargin;
28
private int TopMargin;
29
private int RightMargin;
30
private int BottomMargin;
31
32
private float CurrentY; // A parameter that keep track on the y coordinate of the page, so the next object to be printed will start from this y coordinate
33
34
private float RowHeaderHeight;
35
private List<float> RowsHeight;
36
private List<float> ColumnsWidth;
37
private float TheDataGridViewWidth;
38
39
// Maintain a generic list to hold start/stop points for the column printing
40
// This will be used for wrapping in situations where the DataGridView will not fit on a single page
41
private List<int[]> mColumnPoints;
42
private List<float> mColumnPointsWidth;
43
private int mColumnPoint;
44
45
// The class constructor
46
public DataGridViewPrinter(DataGridView aDataGridView, PrintDocument aPrintDocument, bool CenterOnPage, bool WithTitle, string aTitleText, Font aTitleFont, Color aTitleColor, bool WithPaging)
47
{
48
TheDataGridView = aDataGridView;
49
ThePrintDocument = aPrintDocument;
50
IsCenterOnPage = CenterOnPage;
51
IsWithTitle = WithTitle;
52
TheTitleText = aTitleText;
53
TheTitleFont = aTitleFont;
54
TheTitleColor = aTitleColor;
55
IsWithPaging = WithPaging;
56
57
PageNumber = 0;
58
59
RowsHeight = new List<float>();
60
ColumnsWidth = new List<float>();
61
62
mColumnPoints = new List<int[]>();
63
mColumnPointsWidth = new List<float>();
64
65
// Claculating the PageWidth and the PageHeight
66
if (!ThePrintDocument.DefaultPageSettings.Landscape)
67
{
68
PageWidth = ThePrintDocument.DefaultPageSettings.PaperSize.Width;
69
PageHeight = ThePrintDocument.DefaultPageSettings.PaperSize.Height;
70
}
71
else
72
{
73
PageHeight = ThePrintDocument.DefaultPageSettings.PaperSize.Width;
74
PageWidth = ThePrintDocument.DefaultPageSettings.PaperSize.Height;
75
}
76
77
// Claculating the page margins
78
LeftMargin = ThePrintDocument.DefaultPageSettings.Margins.Left;
79
TopMargin = ThePrintDocument.DefaultPageSettings.Margins.Top;
80
RightMargin = ThePrintDocument.DefaultPageSettings.Margins.Right;
81
BottomMargin = ThePrintDocument.DefaultPageSettings.Margins.Bottom;
82
83
// First, the current row to be printed is the first row in the DataGridView control
84
CurrentRow = 0;
85
}
86
87
// The function that calculate the height of each row (including the header row), the width of each column (according to the longest text in all its cells including the header cell), and the whole DataGridView width
88
private void Calculate(Graphics g)
89
{
90
if (PageNumber == 0) // Just calculate once
91
{
92
SizeF tmpSize = new SizeF();
93
Font tmpFont;
94
float tmpWidth;
95
96
TheDataGridViewWidth = 0;
97
for (int i = 0; i < TheDataGridView.Columns.Count; i++)
98
{
99
tmpFont = TheDataGridView.ColumnHeadersDefaultCellStyle.Font;
100
if (tmpFont == null) // If there is no special HeaderFont style, then use the default DataGridView font style
101
tmpFont = TheDataGridView.DefaultCellStyle.Font;
102
103
tmpSize = g.MeasureString(TheDataGridView.Columns[i].HeaderText, tmpFont);
104
tmpWidth = tmpSize.Width;
105
RowHeaderHeight = tmpSize.Height;
106
107
for (int j = 0; j < TheDataGridView.Rows.Count; j++)
108
{
109
tmpFont = TheDataGridView.Rows[j].DefaultCellStyle.Font;
110
if (tmpFont == null) // If the there is no special font style of the CurrentRow, then use the default one associated with the DataGridView control
111
tmpFont = TheDataGridView.DefaultCellStyle.Font;
112
113
tmpSize = g.MeasureString("Anything", tmpFont);
114
RowsHeight.Add(tmpSize.Height);
115
116
tmpSize = g.MeasureString(TheDataGridView.Rows[j].Cells[i].EditedFormattedValue.ToString(), tmpFont);
117
if (tmpSize.Width > tmpWidth)
118
tmpWidth = tmpSize.Width;
119
}
120
if (TheDataGridView.Columns[i].Visible)
121
TheDataGridViewWidth += tmpWidth;
122
ColumnsWidth.Add(tmpWidth);
123
}
124
125
// Define the start/stop column points based on the page width and the DataGridView Width
126
// We will use this to determine the columns which are drawn on each page and how wrapping will be handled
127
// By default, the wrapping will occurr such that the maximum number of columns for a page will be determine
128
int k;
129
130
int mStartPoint = 0;
131
for (k = 0; k < TheDataGridView.Columns.Count; k++)
132
if (TheDataGridView.Columns[k].Visible)
133
{
134
mStartPoint = k;
135
break;
136
}
137
138
int mEndPoint = TheDataGridView.Columns.Count;
139
for (k = TheDataGridView.Columns.Count - 1; k >= 0; k--)
140
if (TheDataGridView.Columns[k].Visible)
141
{
142
mEndPoint = k + 1;
143
break;
144
}
145
146
float mTempWidth = TheDataGridViewWidth;
147
float mTempPrintArea = (float)PageWidth - (float)LeftMargin - (float)RightMargin;
148
149
// We only care about handling where the total datagridview width is bigger then the print area
150
if (TheDataGridViewWidth > mTempPrintArea)
151
{
152
mTempWidth = 0.0F;
153
for (k = 0; k < TheDataGridView.Columns.Count; k++)
154
{
155
if (TheDataGridView.Columns[k].Visible)
156
{
157
mTempWidth += ColumnsWidth[k];
158
// If the width is bigger than the page area, then define a new column print range
159
if (mTempWidth > mTempPrintArea)
160
{
161
mTempWidth -= ColumnsWidth[k];
162
mColumnPoints.Add(new int[] { mStartPoint, mEndPoint });
163
mColumnPointsWidth.Add(mTempWidth);
164
mStartPoint = k;
165
mTempWidth = ColumnsWidth[k];
166
}
167
}
168
// Our end point is actually one index above the current index
169
mEndPoint = k + 1;
170
}
171
}
172
// Add the last set of columns
173
mColumnPoints.Add(new int[] { mStartPoint, mEndPoint });
174
mColumnPointsWidth.Add(mTempWidth);
175
mColumnPoint = 0;
176
}
177
}
178
179
// The funtion that print the title, page number, and the header row
180
private void DrawHeader(Graphics g)
181
{
182
CurrentY = (float)TopMargin;
183
184
// Printing the page number (if isWithPaging is set to true)
185
if (IsWithPaging)
186
{
187
PageNumber++;
188
string PageString = "Page " + PageNumber.ToString();
189
190
StringFormat PageStringFormat = new StringFormat();
191
PageStringFormat.Trimming = StringTrimming.Word;
192
PageStringFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.LineLimit | StringFormatFlags.NoClip;
193
PageStringFormat.Alignment = StringAlignment.Far;
194
195
Font PageStringFont = new Font("Tahoma", 8, FontStyle.Regular, GraphicsUnit.Point);
196
197
RectangleF PageStringRectangle = new RectangleF((float)LeftMargin, CurrentY, (float)PageWidth - (float)RightMargin - (float)LeftMargin, g.MeasureString(PageString, PageStringFont).Height);
198
199
g.DrawString(PageString, PageStringFont, new SolidBrush(Color.Black), PageStringRectangle, PageStringFormat);
200
201
CurrentY += g.MeasureString(PageString, PageStringFont).Height;
202
}
203
204
// Printing the title (if IsWithTitle is set to true)
205
if (IsWithTitle)
206
{
207
StringFormat TitleFormat = new StringFormat();
208
TitleFormat.Trimming = StringTrimming.Word;
209
TitleFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.LineLimit | StringFormatFlags.NoClip;
210
if (IsCenterOnPage)
211
TitleFormat.Alignment = StringAlignment.Center;
212
else
213
TitleFormat.Alignment = StringAlignment.Near;
214
215
RectangleF TitleRectangle = new RectangleF((float)LeftMargin, CurrentY, (float)PageWidth - (float)RightMargin - (float)LeftMargin, g.MeasureString(TheTitleText, TheTitleFont).Height);
216
217
g.DrawString(TheTitleText, TheTitleFont, new SolidBrush(TheTitleColor), TitleRectangle, TitleFormat);
218
219
CurrentY += g.MeasureString(TheTitleText, TheTitleFont).Height;
220
}
221
222
// Calculating the starting x coordinate that the printing process will start from
223
float CurrentX = (float)LeftMargin;
224
if (IsCenterOnPage)
225
CurrentX += (((float)PageWidth - (float)RightMargin - (float)LeftMargin) - mColumnPointsWidth[mColumnPoint]) / 2.0F;
226
227
// Setting the HeaderFore style
228
Color HeaderForeColor = TheDataGridView.ColumnHeadersDefaultCellStyle.ForeColor;
229
if (HeaderForeColor.IsEmpty) // If there is no special HeaderFore style, then use the default DataGridView style
230
HeaderForeColor = TheDataGridView.DefaultCellStyle.ForeColor;
231
SolidBrush HeaderForeBrush = new SolidBrush(HeaderForeColor);
232
233
// Setting the HeaderBack style
234
Color HeaderBackColor = TheDataGridView.ColumnHeadersDefaultCellStyle.BackColor;
235
if (HeaderBackColor.IsEmpty) // If there is no special HeaderBack style, then use the default DataGridView style
236
HeaderBackColor = TheDataGridView.DefaultCellStyle.BackColor;
237
SolidBrush HeaderBackBrush = new SolidBrush(HeaderBackColor);
238
239
// Setting the LinePen that will be used to draw lines and rectangles (derived from the GridColor property of the DataGridView control)
240
Pen TheLinePen = new Pen(TheDataGridView.GridColor, 1);
241
242
// Setting the HeaderFont style
243
Font HeaderFont = TheDataGridView.ColumnHeadersDefaultCellStyle.Font;
244
if (HeaderFont == null) // If there is no special HeaderFont style, then use the default DataGridView font style
245
HeaderFont = TheDataGridView.DefaultCellStyle.Font;
246
247
// Calculating and drawing the HeaderBounds
248
RectangleF HeaderBounds = new RectangleF(CurrentX, CurrentY, mColumnPointsWidth[mColumnPoint], RowHeaderHeight);
249
g.FillRectangle(HeaderBackBrush, HeaderBounds);
250
251
// Setting the format that will be used to print each cell of the header row
252
StringFormat CellFormat = new StringFormat();
253
CellFormat.Trimming = StringTrimming.Word;
254
CellFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.LineLimit | StringFormatFlags.NoClip;
255
256
// Printing each visible cell of the header row
257
RectangleF CellBounds;
258
float ColumnWidth;
259
for (int i = (int)mColumnPoints[mColumnPoint].GetValue(0); i < (int)mColumnPoints[mColumnPoint].GetValue(1); i++)
260
{
261
if (!TheDataGridView.Columns[i].Visible) continue; // If the column is not visible then ignore this iteration
262
263
ColumnWidth = ColumnsWidth[i];
264
265
// Check the CurrentCell alignment and apply it to the CellFormat
266
if (TheDataGridView.ColumnHeadersDefaultCellStyle.Alignment.ToString().Contains("Right"))
267
CellFormat.Alignment = StringAlignment.Far;
268
else if (TheDataGridView.ColumnHeadersDefaultCellStyle.Alignment.ToString().Contains("Center"))
269
CellFormat.Alignment = StringAlignment.Center;
270
else
271
CellFormat.Alignment = StringAlignment.Near;
272
273
CellBounds = new RectangleF(CurrentX, CurrentY, ColumnWidth, RowHeaderHeight);
274
275
// Printing the cell text
276
g.DrawString(TheDataGridView.Columns[i].HeaderText, HeaderFont, HeaderForeBrush, CellBounds, CellFormat);
277
278
// Drawing the cell bounds
279
if (TheDataGridView.RowHeadersBorderStyle != DataGridViewHeaderBorderStyle.None) // Draw the cell border only if the HeaderBorderStyle is not None
280
g.DrawRectangle(TheLinePen, CurrentX, CurrentY, ColumnWidth, RowHeaderHeight);
281
282
CurrentX += ColumnWidth;
283
}
284
285
CurrentY += RowHeaderHeight;
286
}
287
288
// The function that print a bunch of rows that fit in one page
289
// When it returns true, meaning that there are more rows still not printed, so another PagePrint action is required
290
// When it returns false, meaning that all rows are printed (the CureentRow parameter reaches the last row of the DataGridView control) and no further PagePrint action is required
291
private bool DrawRows(Graphics g)
292
{
293
// Setting the LinePen that will be used to draw lines and rectangles (derived from the GridColor property of the DataGridView control)
294
Pen TheLinePen = new Pen(TheDataGridView.GridColor, 1);
295
296
// The style paramters that will be used to print each cell
297
Font RowFont;
298
Color RowForeColor;
299
Color RowBackColor;
300
SolidBrush RowForeBrush;
301
SolidBrush RowBackBrush;
302
SolidBrush RowAlternatingBackBrush;
303
304
// Setting the format that will be used to print each cell
305
StringFormat CellFormat = new StringFormat();
306
CellFormat.Trimming = StringTrimming.Word;
307
CellFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.LineLimit;
308
309
// Printing each visible cell
310
RectangleF RowBounds;
311
float CurrentX;
312
float ColumnWidth;
313
while (CurrentRow < TheDataGridView.Rows.Count)
314
{
315
if (TheDataGridView.Rows[CurrentRow].Visible) // Print the cells of the CurrentRow only if that row is visible
316
{
317
// Setting the row font style
318
RowFont = TheDataGridView.Rows[CurrentRow].DefaultCellStyle.Font;
319
if (RowFont == null) // If the there is no special font style of the CurrentRow, then use the default one associated with the DataGridView control
320
RowFont = TheDataGridView.DefaultCellStyle.Font;
321
322
// Setting the RowFore style
323
RowForeColor = TheDataGridView.Rows[CurrentRow].DefaultCellStyle.ForeColor;
324
if (RowForeColor.IsEmpty) // If the there is no special RowFore style of the CurrentRow, then use the default one associated with the DataGridView control
325
RowForeColor = TheDataGridView.DefaultCellStyle.ForeColor;
326
RowForeBrush = new SolidBrush(RowForeColor);
327
328
// Setting the RowBack (for even rows) and the RowAlternatingBack (for odd rows) styles
329
RowBackColor = TheDataGridView.Rows[CurrentRow].DefaultCellStyle.BackColor;
330
if (RowBackColor.IsEmpty) // If the there is no special RowBack style of the CurrentRow, then use the default one associated with the DataGridView control
331
{
332
RowBackBrush = new SolidBrush(TheDataGridView.DefaultCellStyle.BackColor);
333
RowAlternatingBackBrush = new SolidBrush(TheDataGridView.AlternatingRowsDefaultCellStyle.BackColor);
334
}
335
else // If the there is a special RowBack style of the CurrentRow, then use it for both the RowBack and the RowAlternatingBack styles
336
{
337
RowBackBrush = new SolidBrush(RowBackColor);
338
RowAlternatingBackBrush = new SolidBrush(RowBackColor);
339
}
340
341
// Calculating the starting x coordinate that the printing process will start from
342
CurrentX = (float)LeftMargin;
343
if (IsCenterOnPage)
344
CurrentX += (((float)PageWidth - (float)RightMargin - (float)LeftMargin) - mColumnPointsWidth[mColumnPoint]) / 2.0F;
345
346
// Calculating the entire CurrentRow bounds
347
RowBounds = new RectangleF(CurrentX, CurrentY, mColumnPointsWidth[mColumnPoint], RowsHeight[CurrentRow]);
348
349
// Filling the back of the CurrentRow
350
if (CurrentRow % 2 == 0)
351
g.FillRectangle(RowBackBrush, RowBounds);
352
else
353
g.FillRectangle(RowAlternatingBackBrush, RowBounds);
354
355
// Printing each visible cell of the CurrentRow
356
for (int CurrentCell = (int)mColumnPoints[mColumnPoint].GetValue(0); CurrentCell < (int)mColumnPoints[mColumnPoint].GetValue(1); CurrentCell++)
357
{
358
if (!TheDataGridView.Columns[CurrentCell].Visible) continue; // If the cell is belong to invisible column, then ignore this iteration
359
360
// Check the CurrentCell alignment and apply it to the CellFormat
361
if (TheDataGridView.Columns[CurrentCell].DefaultCellStyle.Alignment.ToString().Contains("Right"))
362
CellFormat.Alignment = StringAlignment.Far;
363
else if (TheDataGridView.Columns[CurrentCell].DefaultCellStyle.Alignment.ToString().Contains("Center"))
364
CellFormat.Alignment = StringAlignment.Center;
365
else
366
CellFormat.Alignment = StringAlignment.Near;
367
368
ColumnWidth = ColumnsWidth[CurrentCell];
369
RectangleF CellBounds = new RectangleF(CurrentX, CurrentY, ColumnWidth, RowsHeight[CurrentRow]);
370
371
// Printing the cell text
372
g.DrawString(TheDataGridView.Rows[CurrentRow].Cells[CurrentCell].EditedFormattedValue.ToString(), RowFont, RowForeBrush, CellBounds, CellFormat);
373
374
// Drawing the cell bounds
375
if (TheDataGridView.CellBorderStyle != DataGridViewCellBorderStyle.None) // Draw the cell border only if the CellBorderStyle is not None
376
g.DrawRectangle(TheLinePen, CurrentX, CurrentY, ColumnWidth, RowsHeight[CurrentRow]);
377
378
CurrentX += ColumnWidth;
379
}
380
CurrentY += RowsHeight[CurrentRow];
381
382
// Checking if the CurrentY is exceeds the page boundries
383
// If so then exit the function and returning true meaning another PagePrint action is required
384
if ((int)CurrentY > (PageHeight - TopMargin - BottomMargin))
385
{
386
CurrentRow++;
387
return true;
388
}
389
}
390
CurrentRow++;
391
}
392
393
CurrentRow = 0;
394
mColumnPoint++; // Continue to print the next group of columns
395
396
if (mColumnPoint == mColumnPoints.Count) // Which means all columns are printed
397
{
398
mColumnPoint = 0;
399
return false;
400
}
401
else
402
return true;
403
}
404
405
// The method that calls all other functions
406
public bool DrawDataGridView(Graphics g)
407
{
408
try
409
{
410
Calculate(g);
411
DrawHeader(g);
412
bool bContinue = DrawRows(g);
413
return bContinue;
414
}
415
catch (Exception ex)
416
{
417
MessageBox.Show("Operation failed: " + ex.Message.ToString(), Application.ProductName + " - Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
418
return false;
419
}
420
}
421
}
422
using System;2
using System.Text;3
using System.Collections;4
using System.Collections.Generic;5
using System.Drawing;6
using System.Drawing.Printing;7
using System.Data;8
using System.Windows.Forms;9

10
class DataGridViewPrinter11
{12
private DataGridView TheDataGridView; // The DataGridView Control which will be printed13
private PrintDocument ThePrintDocument; // The PrintDocument to be used for printing14
private bool IsCenterOnPage; // Determine if the report will be printed in the Top-Center of the page15
private bool IsWithTitle; // Determine if the page contain title text16
private string TheTitleText; // The title text to be printed in each page (if IsWithTitle is set to true)17
private Font TheTitleFont; // The font to be used with the title text (if IsWithTitle is set to true)18
private Color TheTitleColor; // The color to be used with the title text (if IsWithTitle is set to true)19
private bool IsWithPaging; // Determine if paging is used20

21
static int CurrentRow; // A static parameter that keep track on which Row (in the DataGridView control) that should be printed22

23
static int PageNumber;24

25
private int PageWidth;26
private int PageHeight;27
private int LeftMargin;28
private int TopMargin;29
private int RightMargin;30
private int BottomMargin;31

32
private float CurrentY; // A parameter that keep track on the y coordinate of the page, so the next object to be printed will start from this y coordinate33

34
private float RowHeaderHeight;35
private List<float> RowsHeight;36
private List<float> ColumnsWidth;37
private float TheDataGridViewWidth;38
39
// Maintain a generic list to hold start/stop points for the column printing40
// This will be used for wrapping in situations where the DataGridView will not fit on a single page41
private List<int[]> mColumnPoints;42
private List<float> mColumnPointsWidth;43
private int mColumnPoint;44
45
// The class constructor46
public DataGridViewPrinter(DataGridView aDataGridView, PrintDocument aPrintDocument, bool CenterOnPage, bool WithTitle, string aTitleText, Font aTitleFont, Color aTitleColor, bool WithPaging)47
{48
TheDataGridView = aDataGridView;49
ThePrintDocument = aPrintDocument;50
IsCenterOnPage = CenterOnPage;51
IsWithTitle = WithTitle;52
TheTitleText = aTitleText;53
TheTitleFont = aTitleFont;54
TheTitleColor = aTitleColor;55
IsWithPaging = WithPaging;56

57
PageNumber = 0;58

59
RowsHeight = new List<float>();60
ColumnsWidth = new List<float>();61

62
mColumnPoints = new List<int[]>();63
mColumnPointsWidth = new List<float>();64

65
// Claculating the PageWidth and the PageHeight66
if (!ThePrintDocument.DefaultPageSettings.Landscape)67
{68
PageWidth = ThePrintDocument.DefaultPageSettings.PaperSize.Width;69
PageHeight = ThePrintDocument.DefaultPageSettings.PaperSize.Height;70
}71
else72
{73
PageHeight = ThePrintDocument.DefaultPageSettings.PaperSize.Width;74
PageWidth = ThePrintDocument.DefaultPageSettings.PaperSize.Height;75
}76

77
// Claculating the page margins78
LeftMargin = ThePrintDocument.DefaultPageSettings.Margins.Left;79
TopMargin = ThePrintDocument.DefaultPageSettings.Margins.Top;80
RightMargin = ThePrintDocument.DefaultPageSettings.Margins.Right;81
BottomMargin = ThePrintDocument.DefaultPageSettings.Margins.Bottom;82

83
// First, the current row to be printed is the first row in the DataGridView control84
CurrentRow = 0;85
}86

87
// The function that calculate the height of each row (including the header row), the width of each column (according to the longest text in all its cells including the header cell), and the whole DataGridView width88
private void Calculate(Graphics g)89
{90
if (PageNumber == 0) // Just calculate once91
{92
SizeF tmpSize = new SizeF();93
Font tmpFont;94
float tmpWidth;95

96
TheDataGridViewWidth = 0;97
for (int i = 0; i < TheDataGridView.Columns.Count; i++)98
{99
tmpFont = TheDataGridView.ColumnHeadersDefaultCellStyle.Font;100
if (tmpFont == null) // If there is no special HeaderFont style, then use the default DataGridView font style101
tmpFont = TheDataGridView.DefaultCellStyle.Font;102

103
tmpSize = g.MeasureString(TheDataGridView.Columns[i].HeaderText, tmpFont);104
tmpWidth = tmpSize.Width;105
RowHeaderHeight = tmpSize.Height;106

107
for (int j = 0; j < TheDataGridView.Rows.Count; j++)108
{109
tmpFont = TheDataGridView.Rows[j].DefaultCellStyle.Font;110
if (tmpFont == null) // If the there is no special font style of the CurrentRow, then use the default one associated with the DataGridView control111
tmpFont = TheDataGridView.DefaultCellStyle.Font;112

113
tmpSize = g.MeasureString("Anything", tmpFont);114
RowsHeight.Add(tmpSize.Height);115

116
tmpSize = g.MeasureString(TheDataGridView.Rows[j].Cells[i].EditedFormattedValue.ToString(), tmpFont);117
if (tmpSize.Width > tmpWidth)118
tmpWidth = tmpSize.Width;119
}120
if (TheDataGridView.Columns[i].Visible)121
TheDataGridViewWidth += tmpWidth;122
ColumnsWidth.Add(tmpWidth);123
}124

125
// Define the start/stop column points based on the page width and the DataGridView Width126
// We will use this to determine the columns which are drawn on each page and how wrapping will be handled127
// By default, the wrapping will occurr such that the maximum number of columns for a page will be determine128
int k;129

130
int mStartPoint = 0;131
for (k = 0; k < TheDataGridView.Columns.Count; k++)132
if (TheDataGridView.Columns[k].Visible)133
{134
mStartPoint = k;135
break;136
}137

138
int mEndPoint = TheDataGridView.Columns.Count;139
for (k = TheDataGridView.Columns.Count - 1; k >= 0; k--)140
if (TheDataGridView.Columns[k].Visible)141
{142
mEndPoint = k + 1;143
break;144
}145

146
float mTempWidth = TheDataGridViewWidth;147
float mTempPrintArea = (float)PageWidth - (float)LeftMargin - (float)RightMargin;148
149
// We only care about handling where the total datagridview width is bigger then the print area150
if (TheDataGridViewWidth > mTempPrintArea)151
{152
mTempWidth = 0.0F;153
for (k = 0; k < TheDataGridView.Columns.Count; k++)154
{155
if (TheDataGridView.Columns[k].Visible)156
{157
mTempWidth += ColumnsWidth[k];158
// If the width is bigger than the page area, then define a new column print range159
if (mTempWidth > mTempPrintArea)160
{161
mTempWidth -= ColumnsWidth[k];162
mColumnPoints.Add(new int[] { mStartPoint, mEndPoint });163
mColumnPointsWidth.Add(mTempWidth);164
mStartPoint = k;165
mTempWidth = ColumnsWidth[k];166
}167
}168
// Our end point is actually one index above the current index169
mEndPoint = k + 1;170
}171
}172
// Add the last set of columns173
mColumnPoints.Add(new int[] { mStartPoint, mEndPoint });174
mColumnPointsWidth.Add(mTempWidth);175
mColumnPoint = 0;176
}177
}178

179
// The funtion that print the title, page number, and the header row180
private void DrawHeader(Graphics g)181
{182
CurrentY = (float)TopMargin;183

184
// Printing the page number (if isWithPaging is set to true)185
if (IsWithPaging)186
{187
PageNumber++;188
string PageString = "Page " + PageNumber.ToString();189

190
StringFormat PageStringFormat = new StringFormat();191
PageStringFormat.Trimming = StringTrimming.Word;192
PageStringFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.LineLimit | StringFormatFlags.NoClip;193
PageStringFormat.Alignment = StringAlignment.Far;194

195
Font PageStringFont = new Font("Tahoma", 8, FontStyle.Regular, GraphicsUnit.Point);196

197
RectangleF PageStringRectangle = new RectangleF((float)LeftMargin, CurrentY, (float)PageWidth - (float)RightMargin - (float)LeftMargin, g.MeasureString(PageString, PageStringFont).Height);198

199
g.DrawString(PageString, PageStringFont, new SolidBrush(Color.Black), PageStringRectangle, PageStringFormat);200

201
CurrentY += g.MeasureString(PageString, PageStringFont).Height;202
}203

204
// Printing the title (if IsWithTitle is set to true)205
if (IsWithTitle)206
{207
StringFormat TitleFormat = new StringFormat();208
TitleFormat.Trimming = StringTrimming.Word;209
TitleFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.LineLimit | StringFormatFlags.NoClip;210
if (IsCenterOnPage)211
TitleFormat.Alignment = StringAlignment.Center;212
else213
TitleFormat.Alignment = StringAlignment.Near;214

215
RectangleF TitleRectangle = new RectangleF((float)LeftMargin, CurrentY, (float)PageWidth - (float)RightMargin - (float)LeftMargin, g.MeasureString(TheTitleText, TheTitleFont).Height);216

217
g.DrawString(TheTitleText, TheTitleFont, new SolidBrush(TheTitleColor), TitleRectangle, TitleFormat);218

219
CurrentY += g.MeasureString(TheTitleText, TheTitleFont).Height;220
}221

222
// Calculating the starting x coordinate that the printing process will start from223
float CurrentX = (float)LeftMargin;224
if (IsCenterOnPage) 225
CurrentX += (((float)PageWidth - (float)RightMargin - (float)LeftMargin) - mColumnPointsWidth[mColumnPoint]) / 2.0F;226

227
// Setting the HeaderFore style228
Color HeaderForeColor = TheDataGridView.ColumnHeadersDefaultCellStyle.ForeColor;229
if (HeaderForeColor.IsEmpty) // If there is no special HeaderFore style, then use the default DataGridView style230
HeaderForeColor = TheDataGridView.DefaultCellStyle.ForeColor;231
SolidBrush HeaderForeBrush = new SolidBrush(HeaderForeColor);232

233
// Setting the HeaderBack style234
Color HeaderBackColor = TheDataGridView.ColumnHeadersDefaultCellStyle.BackColor;235
if (HeaderBackColor.IsEmpty) // If there is no special HeaderBack style, then use the default DataGridView style236
HeaderBackColor = TheDataGridView.DefaultCellStyle.BackColor;237
SolidBrush HeaderBackBrush = new SolidBrush(HeaderBackColor);238

239
// Setting the LinePen that will be used to draw lines and rectangles (derived from the GridColor property of the DataGridView control)240
Pen TheLinePen = new Pen(TheDataGridView.GridColor, 1);241

242
// Setting the HeaderFont style243
Font HeaderFont = TheDataGridView.ColumnHeadersDefaultCellStyle.Font;244
if (HeaderFont == null) // If there is no special HeaderFont style, then use the default DataGridView font style245
HeaderFont = TheDataGridView.DefaultCellStyle.Font;246

247
// Calculating and drawing the HeaderBounds 248
RectangleF HeaderBounds = new RectangleF(CurrentX, CurrentY, mColumnPointsWidth[mColumnPoint], RowHeaderHeight);249
g.FillRectangle(HeaderBackBrush, HeaderBounds);250

251
// Setting the format that will be used to print each cell of the header row252
StringFormat CellFormat = new StringFormat();253
CellFormat.Trimming = StringTrimming.Word;254
CellFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.LineLimit | StringFormatFlags.NoClip;255

256
// Printing each visible cell of the header row257
RectangleF CellBounds;258
float ColumnWidth; 259
for (int i = (int)mColumnPoints[mColumnPoint].GetValue(0); i < (int)mColumnPoints[mColumnPoint].GetValue(1); i++)260
{261
if (!TheDataGridView.Columns[i].Visible) continue; // If the column is not visible then ignore this iteration262

263
ColumnWidth = ColumnsWidth[i];264

265
// Check the CurrentCell alignment and apply it to the CellFormat266
if (TheDataGridView.ColumnHeadersDefaultCellStyle.Alignment.ToString().Contains("Right"))267
CellFormat.Alignment = StringAlignment.Far;268
else if (TheDataGridView.ColumnHeadersDefaultCellStyle.Alignment.ToString().Contains("Center"))269
CellFormat.Alignment = StringAlignment.Center;270
else271
CellFormat.Alignment = StringAlignment.Near;272

273
CellBounds = new RectangleF(CurrentX, CurrentY, ColumnWidth, RowHeaderHeight);274

275
// Printing the cell text276
g.DrawString(TheDataGridView.Columns[i].HeaderText, HeaderFont, HeaderForeBrush, CellBounds, CellFormat);277

278
// Drawing the cell bounds279
if (TheDataGridView.RowHeadersBorderStyle != DataGridViewHeaderBorderStyle.None) // Draw the cell border only if the HeaderBorderStyle is not None280
g.DrawRectangle(TheLinePen, CurrentX, CurrentY, ColumnWidth, RowHeaderHeight);281

282
CurrentX += ColumnWidth;283
}284

285
CurrentY += RowHeaderHeight;286
}287

288
// The function that print a bunch of rows that fit in one page289
// When it returns true, meaning that there are more rows still not printed, so another PagePrint action is required290
// When it returns false, meaning that all rows are printed (the CureentRow parameter reaches the last row of the DataGridView control) and no further PagePrint action is required291
private bool DrawRows(Graphics g)292
{293
// Setting the LinePen that will be used to draw lines and rectangles (derived from the GridColor property of the DataGridView control)294
Pen TheLinePen = new Pen(TheDataGridView.GridColor, 1);295

296
// The style paramters that will be used to print each cell297
Font RowFont;298
Color RowForeColor;299
Color RowBackColor;300
SolidBrush RowForeBrush;301
SolidBrush RowBackBrush;302
SolidBrush RowAlternatingBackBrush;303

304
// Setting the format that will be used to print each cell305
StringFormat CellFormat = new StringFormat();306
CellFormat.Trimming = StringTrimming.Word;307
CellFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.LineLimit;308

309
// Printing each visible cell310
RectangleF RowBounds;311
float CurrentX;312
float ColumnWidth;313
while (CurrentRow < TheDataGridView.Rows.Count)314
{315
if (TheDataGridView.Rows[CurrentRow].Visible) // Print the cells of the CurrentRow only if that row is visible316
{317
// Setting the row font style318
RowFont = TheDataGridView.Rows[CurrentRow].DefaultCellStyle.Font;319
if (RowFont == null) // If the there is no special font style of the CurrentRow, then use the default one associated with the DataGridView control320
RowFont = TheDataGridView.DefaultCellStyle.Font;321

322
// Setting the RowFore style323
RowForeColor = TheDataGridView.Rows[CurrentRow].DefaultCellStyle.ForeColor;324
if (RowForeColor.IsEmpty) // If the there is no special RowFore style of the CurrentRow, then use the default one associated with the DataGridView control325
RowForeColor = TheDataGridView.DefaultCellStyle.ForeColor;326
RowForeBrush = new SolidBrush(RowForeColor);327

328
// Setting the RowBack (for even rows) and the RowAlternatingBack (for odd rows) styles329
RowBackColor = TheDataGridView.Rows[CurrentRow].DefaultCellStyle.BackColor;330
if (RowBackColor.IsEmpty) // If the there is no special RowBack style of the CurrentRow, then use the default one associated with the DataGridView control331
{332
RowBackBrush = new SolidBrush(TheDataGridView.DefaultCellStyle.BackColor);333
RowAlternatingBackBrush = new SolidBrush(TheDataGridView.AlternatingRowsDefaultCellStyle.BackColor);334
}335
else // If the there is a special RowBack style of the CurrentRow, then use it for both the RowBack and the RowAlternatingBack styles336
{337
RowBackBrush = new SolidBrush(RowBackColor);338
RowAlternatingBackBrush = new SolidBrush(RowBackColor);339
}340

341
// Calculating the starting x coordinate that the printing process will start from342
CurrentX = (float)LeftMargin;343
if (IsCenterOnPage) 344
CurrentX += (((float)PageWidth - (float)RightMargin - (float)LeftMargin) - mColumnPointsWidth[mColumnPoint]) / 2.0F;345

346
// Calculating the entire CurrentRow bounds 347
RowBounds = new RectangleF(CurrentX, CurrentY, mColumnPointsWidth[mColumnPoint], RowsHeight[CurrentRow]);348

349
// Filling the back of the CurrentRow350
if (CurrentRow % 2 == 0)351
g.FillRectangle(RowBackBrush, RowBounds);352
else353
g.FillRectangle(RowAlternatingBackBrush, RowBounds);354

355
// Printing each visible cell of the CurrentRow 356
for (int CurrentCell = (int)mColumnPoints[mColumnPoint].GetValue(0); CurrentCell < (int)mColumnPoints[mColumnPoint].GetValue(1); CurrentCell++)357
{358
if (!TheDataGridView.Columns[CurrentCell].Visible) continue; // If the cell is belong to invisible column, then ignore this iteration359

360
// Check the CurrentCell alignment and apply it to the CellFormat361
if (TheDataGridView.Columns[CurrentCell].DefaultCellStyle.Alignment.ToString().Contains("Right"))362
CellFormat.Alignment = StringAlignment.Far;363
else if (TheDataGridView.Columns[CurrentCell].DefaultCellStyle.Alignment.ToString().Contains("Center"))364
CellFormat.Alignment = StringAlignment.Center;365
else366
CellFormat.Alignment = StringAlignment.Near;367
368
ColumnWidth = ColumnsWidth[CurrentCell];369
RectangleF CellBounds = new RectangleF(CurrentX, CurrentY, ColumnWidth, RowsHeight[CurrentRow]);370

371
// Printing the cell text372
g.DrawString(TheDataGridView.Rows[CurrentRow].Cells[CurrentCell].EditedFormattedValue.ToString(), RowFont, RowForeBrush, CellBounds, CellFormat);373
374
// Drawing the cell bounds375
if (TheDataGridView.CellBorderStyle != DataGridViewCellBorderStyle.None) // Draw the cell border only if the CellBorderStyle is not None376
g.DrawRectangle(TheLinePen, CurrentX, CurrentY, ColumnWidth, RowsHeight[CurrentRow]);377

378
CurrentX += ColumnWidth;379
}380
CurrentY += RowsHeight[CurrentRow];381

382
// Checking if the CurrentY is exceeds the page boundries383
// If so then exit the function and returning true meaning another PagePrint action is required384
if ((int)CurrentY > (PageHeight - TopMargin - BottomMargin))385
{386
CurrentRow++;387
return true;388
}389
}390
CurrentRow++;391
}392

393
CurrentRow = 0;394
mColumnPoint++; // Continue to print the next group of columns395

396
if (mColumnPoint == mColumnPoints.Count) // Which means all columns are printed397
{398
mColumnPoint = 0;399
return false;400
}401
else402
return true;403
}404

405
// The method that calls all other functions406
public bool DrawDataGridView(Graphics g)407
{408
try409
{410
Calculate(g);411
DrawHeader(g);412
bool bContinue = DrawRows(g);413
return bContinue;414
}415
catch (Exception ex)416
{417
MessageBox.Show("Operation failed: " + ex.Message.ToString(), Application.ProductName + " - Error", MessageBoxButtons.OK, MessageBoxIcon.Error);418
return false;419
}420
}421
}422

下载源代码



浙公网安备 33010602011771号