秀纳

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

 

  1using System;
  2using System.Text;
  3using System.Collections;
  4using System.Collections.Generic;
  5using System.Drawing;
  6using System.Drawing.Printing;
  7using System.Data;
  8using System.Windows.Forms;
  9
 10class 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

下载源代码
posted on 2006-10-17 21:08  秀纳  阅读(1330)  评论(1)    收藏  举报