如何在 C# 和 .NET 中打印 DataGrid

????????DataGrid 是 .NET 架構中一個功能極其豐富的組件,或許也是最復雜的組件之一。寫這篇文章是為了回答“我到底該如何打印 DataGrid 及其內容”這個問題。最初即興的建議是使用我的屏幕截圖文章來截取表單,但這當然無法解決打印 DataGrid 中虛擬顯示的無數行數據的問題。后來想了想,這應該很簡單,我只需使用 GDI+ 遍歷 DataGrid 中的行并打印其內容即可。其實,DataGrid 比這更復雜一些,因為它本身并不包含數據。數據包含在 DataSet 中。因此,最終確定的方法是從 DataGrid 中捕獲顏色和字體屬性用于打印輸出,并從 DataSet 中捕獲行中的信息。為了將 DataGridPrinter 的繪制功能封裝到 Printer 中,我創建了 DataGridPrinter 類,如下圖 2 所示。此類將 DataGrid、PrintDocument 和 DataTable 傳遞給其構造函數,并利用這些對象將 DataGrid 繪制到打印機。

圖 1. Northwind DataGrid 的打印預覽

圖 2. DataGridPrinter 類 UML 設計(使用 WithClass 2000 進行逆向工程)

????????DataGridPrinter 在表單的構造函數中構建,因此它可以被所有打印功能(打印、打印預覽等)使用。下面是構建 DataGridPrinter 的代碼:

void SetupGridPrinter() ?
{ ?
? ? dataGridPrinter1 =new DataGridPrinter(dataGrid1, printDocument1, ?
? ? dataSet11.Customers); ?
} ?

一旦構建了 DataGridPrinter,您就可以通過在 Print Page 事件處理程序中調用其 DrawDataGrid 方法將 DataGrid 繪制到打印機上:

private void printDocument1_PrintPage(object sender,System.Drawing.Printing.PrintPageEventArgs e) ?
{ ?
? ? Graphics g = e.Graphics; ?
? ? // Draw a label title for the grid ?
? ? DrawTopLabel(g); ?
? ? // draw the datagrid using the DrawDataGrid method passing the Graphics surface ?
? ? bool more = dataGridPrinter1.DrawDataGrid(g); ?
? ? // if there are more pages, set the flag to cause the form to trigger another print page event ?
? ? if (more == true) ?
? ? { ?
? ? ? ? e.HasMorePages =true; ?
? ? ? ? dataGridPrinter1.PageNumber++; ?
? ? } ?
} ?

????????PrintPage 事件由 PrintDocument 中的 Print 方法和 PrintPreviewDialog 的 ShowDialog 方法觸發。下面是窗體將 DataGrid 打印到打印機的方法:

private void PrintMenu_Click(object sender, System.EventArgs e) ?
{ ?
? ? // Initialize the datagrid page and row properties ?
? ? dataGridPrinter1.PageNumber = 1; ?
? ? dataGridPrinter1.RowCount = 0; ?
? ? // Show the Print Dialog to set properties and print the document after ok is pressed. ?
? ? if (printDialog1.ShowDialog() == DialogResult.OK) ?
? ? { ?
? ? ? ? printDocument1.Print(); ?
? ? } ?
} ?

????????現在讓我們來看看 DataGridPrinter 方法的內部實現。DataGridPrinter 類中有兩個主要方法用于執行所有繪制操作:DrawHeader 和 DrawRows。這兩個方法都從 DataGrid 和 DataTable 中提取信息來繪制 DataGrid。以下是繪制 DataGrid 行的方法:

public bool DrawRows(Graphics g) ?
? ? { ?
? ? ? ? try ?
? ? ? ? { ?
? ? ? ? ? ? int lastRowBottom = TopMargin; ?
? ? ? ? ? ? // Create an array to save the horizontal positions for drawing horizontal gridlines ?
? ? ? ? ? ? ArrayList Lines = new ArrayList(); ?
? ? ? ? ? ? // form brushes based on the color properties of the DataGrid ?
? ? ? ? ? ? // These brushes will be used to draw the grid borders and cells ?
? ? ? ? ? ? SolidBrush ForeBrush = new SolidBrush(TheDataGrid.ForeColor); ?
? ? ? ? ? ? SolidBrush BackBrush = new SolidBrush(TheDataGrid.BackColor); ?
? ? ? ? ? ? SolidBrush AlternatingBackBrush = new SolidBrush ?
? ? ? ? ? ? TheDataGrid.AlternatingBackColor); ?
? ? ? ? ? ? Pen TheLinePen = new Pen(TheDataGrid.GridLineColor, 1); ?
? ? ? ? ? ? // Create a format for the cell so that the string in the cell is cut off at the end of ?
? ? ? ? ? ? the column width ?
? ? ? ? ? ? StringFormat cellformat = new StringFormat(); ?
? ? ? ? ? ? cellformat.Trimming = StringTrimming.EllipsisCharacter; ?
? ? ? ? ? ? cellformat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.LineLimit; ?
? ? ? ? ? ? // calculate the column width based on the width of the printed page and the # of ?
? ? ? ? ? ? columns in the DataTable ?
? ? ? ? ? ? // Note: Column Widths can be made variable in a future program by playing with the GridColumnStyles of the ?
? ? ? ? ? ? // DataGrid ?
? ? ? ? ? ? int columnwidth = PageWidth / TheTable.Columns.Count; ?
? ? ? ? ? ? // set the initial row count, this will start at 0 for the first page, and be a different ?
? ? ? ? ? ? value for the 2nd, 3rd, 4th, etc. ?
? ? ? ? ? ? // pages. ?
? ? ? ? ? ? int initialRowCount = RowCount; ?
? ? ? ? ? ? RectangleF RowBounds = new RectangleF(0, 0, 0, 0); ?
? ? ? ? ? ? // draw the rows of the table ??
? ? ? ? ? ? for (int i = initialRowCount; i < TheTable.Rows.Count; i++) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? // get the next DataRow in the DataTable ?
? ? ? ? ? ? ? ? DataRow dr = TheTable.Rows[i]; ?
? ? ? ? ? ? ? ? int startxposition = TheDataGrid.Location.X; ?
? ? ? ? ? ? ? ? // Calculate the row boundary based on teh RowCount and offsets into the page ?
? ? ? ? ? ? ? ? RowBounds.X = TheDataGrid.Location.X; RowBounds.Y = TheDataGrid.Location.Y + ?
? ? ? ? ? ? ? ? ?TopMargin + ((RowCount - initialRowCount) + 1) * (TheDataGrid.Font.SizeInPoints + ?
? ? ? ? ? ? ? ? ?kVerticalCellLeeway); ?
? ? ? ? ? ? ? ? RowBounds.Height = TheDataGrid.Font.SizeInPoints + kVerticalCellLeeway; ?
? ? ? ? ? ? ? ? RowBounds.Width = PageWidth; ?
? ? ? ? ? ? ? ? // save the vertical row positions for drawing grid lines ?
? ? ? ? ? ? ? ? Lines.Add(RowBounds.Bottom); ?
? ? ? ? ? ? ? ? // paint rows differently for alternate row colors ?
? ? ? ? ? ? ? ? if (i % 2 == 0) ?
? ? ? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? ? ? g.FillRectangle(BackBrush, RowBounds); ?
? ? ? ? ? ? ? ? } ?
? ? ? ? ? ? ? ? else ?
? ? ? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? ? ? g.FillRectangle(AlternatingBackBrush, RowBounds); ?
? ? ? ? ? ? ? ? } ?
? ? ? ? ? ? ? ? // Go through each column in the row and draw the information from the ?
? ? ? ? ? ? ? ? DataRowfor(int j = 0; j < TheTable.Columns.Count; j++) ?
? ? ? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? RectangleF cellbounds = new RectangleF(startxposition, ?
? ? ? ? ? ? ? ? TheDataGrid.Location.Y + TopMargin + ((RowCount - initialRowCount) + 1) * ?
? ? ? ? ? ? ? ? (TheDataGrid.Font.SizeInPoints + kVerticalCellLeeway), ?
? ? ? ? ? ? ? ? columnwidth, ?
? ? ? ? ? ? ? ? TheDataGrid.Font.SizeInPoints + kVerticalCellLeeway); ?
? ? ? ? ? ? ? ? // draw the data at the next position in the row ?
? ? ? ? ? ? ? ? if (startxposition + columnwidth <= PageWidth) ?
? ? ? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? ? ? g.DrawString(dr[j].ToString(), TheDataGrid.Font, ForeBrush, cellbounds, cellformat); ?
? ? ? ? ? ? ? ? ? ? lastRowBottom = (int)cellbounds.Bottom; ?
? ? ? ? ? ? ? ? } ?
? ? ? ? ? ? ? ? // increment the column position ?
? ? ? ? ? ? ? ? startxposition = startxposition + columnwidth; ?
? ? ? ? ? ? } ?
? ? ? ? ? ? RowCount++; ?
? ? ? ? ? ? // when we've reached the bottom of the page, draw the horizontal and vertical grid lines and return true ?
? ? ? ? if (RowCount * (TheDataGrid.Font.SizeInPoints + kVerticalCellLeeway) > ?
? ? ? ? PageHeight * PageNumber) - (BottomMargin + TopMargin)) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? DrawHorizontalLines(g, Lines); DrawVerticalGridLines(g, TheLinePen, columnwidth, ?
? ? ? ? ? ? ? ? ?lastRowBottom); ?
? ? ? ? ? ? ? ? return true; ?
? ? ? ? ? ? } ?
? ? ? ? } ?
// when we've reached the end of the table, draw the horizontal and vertical gridlines and return false ?
? ? DrawHorizontalLines(g, Lines); ?
? ? DrawVerticalGridLines(g, TheLinePen, columnwidth, lastRowBottom); ?
? ? return false; ?
} ?
catch (Exception ex) ?
{ ?
MessageBox.Show(ex.Message.ToString()); ?
return false; ?
} ?

????????該方法遍歷 DataTable 中的每一行并繪制數據。該方法使用 DataGrid 的屬性,用適當的顏色繪制每一行,并使用 DataGrid 的字體繪制每個字符串。如果該方法到達頁面底部,則會中斷并返回 true,以便將 DataGrid 的剩余部分打印到下一頁。

改進:

利用???????? DataGrid 的 TableStyles 屬性中存儲的 DataGridColumnStyle 類,可以極大地改進此類。這些屬性允許您為某些列指定不同的列寬以及不同的文本對齊方式。

如果您喜歡此文章,請收藏、點贊、評論,謝謝,祝您快樂每一天。?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/82197.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/82197.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/82197.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C語言 指針(5)

目錄 1.冒泡排序 2.二級指針 3.指針數組 4.指針數組模擬二級數組 1.冒泡排序 1.1 基本概念 冒泡排序&#xff08;Bubble Sort&#xff09; 是一種簡單的排序算法&#xff0c;它重復地遍歷要排序的數列&#xff0c;一次比較兩個元 素&#xff0c;如果它們的順序錯誤就把它…

15前端項目----用戶信息/導航守衛

登錄/注冊 持久存儲用戶信息問題 退出登錄導航守衛解決問題 持久存儲用戶信息 本地存儲&#xff1a;&#xff08;在actions中請求成功時&#xff09; 添加localStorage.setItem(token,result.data.token);獲取存儲&#xff1a;&#xff08;在user倉庫中&#xff0c;state中tok…

RSS 2025|斯坦福提出「統一視頻行動模型UVA」:實現機器人高精度動作推理

導讀 在機器人領域&#xff0c;讓機器人像人類一樣理解視覺信息并做出精準行動&#xff0c;一直是科研人員努力的方向。今天&#xff0c;我們要探討的統一視頻行動模型&#xff08;Unified Video Action Model&#xff0c;UVA&#xff09;&#xff0c;就像給機器人裝上了一個“…

基于論文的大模型應用:基于SmartETL的arXiv論文數據接入與預處理(四)

上一篇介紹了基于SmartETL框架實現arxiv采集處理的基本流程&#xff0c;通過少量的組件定制開發&#xff0c;配合yaml流程配置&#xff0c;實現了復雜的arxiv采集處理。 由于其業務流程復雜&#xff0c;在實際應用中還存在一些不足需要優化。 5. 基于Kafka的任務解耦設計 5.…

Fiori學習專題三十五:Device Adaptation

由于在類似于手機的小面板上顯示時&#xff0c;我們為了留出更多空間展示數據&#xff0c;可以將一些控件折疊。 1.修改HelloPanel.view.xml&#xff0c;加入expandable“{device>/system/phone}” expanded"{ !${device>/system/phone} <mvc:ViewcontrollerNam…

【記錄】HunyuanVideo 文生視頻工作流

HunyuanVideo 文生視頻工作流指南 概述 本指南詳細介紹如何在ComfyUI中使用騰訊混元HunyuanVideo模型進行文本到視頻生成的全流程操作&#xff0c;包含環境配置、模型安裝和工作流使用說明。 參考&#xff1a;https://comfyui-wiki.com/zh/install/install-comfyui/install-c…

統一返回JsonResult踩坑

定義了一個統一返回類&#xff0c;但是沒有給Data 導致沒有get/set方法&#xff0c;請求一直報錯 public class JsonResult<T> {private int code;private String message;private T data;public JsonResult() {}public JsonResult(int code, String message, T data) {…

dubbo-token驗證

服務提供者過濾器 import java.util.Map; import java.util.Objects;/*** title ProviderTokenFilter* description 服務提供者 token 驗證* author zzw* version 1.0.0* create 2025/5/7 22:17**/ Activate(group CommonConstants.PROVIDER) public class ProviderTokenFilt…

沃倫森電氣高壓動態無功補償裝置助力企業電能優化

在工業生產的復雜電能環境中&#xff0c;電能質量直接影響企業的生產效率和運營成本。XX光伏科技有限公司作為一家快速發展的制造企業&#xff0c;隨著生產規模的不斷擴大&#xff0c;其內部電網面臨功率因數過低、電壓波動頻繁等問題&#xff0c;導致供電部門罰款增加、設備故…

基于EFISH-SCB-RK3576工控機/SAIL-RK3576核心板的網絡安全防火墻技術方案?(國產化替代J1900的全棧技術解析)

?基于EFISH-SCB-RK3576/SAIL-RK3576的網絡安全防火墻技術方案? &#xff08;國產化替代J1900的全棧技術解析&#xff09; ?一、硬件架構設計? ?流量處理核心模塊? ?多核異構架構?&#xff1a; ?四核Cortex-A72&#xff08;2.3GHz&#xff09;?&#xff1a;處理深度…

Maven 動態版本與SNAPSHOT機制詳解

&#x1f9d1; 博主簡介&#xff1a;CSDN博客專家&#xff0c;歷代文學網&#xff08;PC端可以訪問&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移動端可微信小程序搜索“歷代文學”&#xff09;總架構師&#xff0c;15年工作經驗&#xff0c;精通Java編…

趣味編程:答案之書

概述&#xff1a;該篇博客主要介紹的是曾經一度風靡全網的答案之書小程序。 目錄 1. 效果展示 2. 源碼展示 3. 代碼邏輯詳解 3.1 頭文件與全局變量 3.2 main函數 3.3 主循環 3. 4 繪制界面 4. 運行問題 5.小結 1. 效果展示 該小程序是動態的效果&#xff0c; 因此實…

多線程初階(2)

說到多線程編程&#xff0c;一定少不了線程安全這個話題。我們前面了解了線程的原理以及線程與進程的關系。線程之間共享資源&#xff0c;這就代表了在多線程編程中一定會產生沖突&#xff0c;所以我們需要在敲代碼時保證線程安全&#xff0c;避免這樣的問題發生。 我們先看一…

【Ubuntu】安裝向日葵遠程控制

前言 在Ubuntu 24.04.2下安裝向日葵遠程控制出錯&#xff0c;少了一些依賴&#xff0c;需要安裝一些依賴。 1.安裝gconf2-common wget http://mirrors.kernel.org/ubuntu/pool/universe/g/gconf/gconf2-common_3.2.6-6ubuntu1_all.deb sudo dpkg -i gconf2-common_3.2.6-6ub…

【Python開源】深度解析:一款高效音頻封面批量刪除工具的設計與實現

&#x1f3b5; 【Python開源】深度解析&#xff1a;一款高效音頻封面批量刪除工具的設計與實現 &#x1f308; 個人主頁&#xff1a;創客白澤 - CSDN博客 &#x1f525; 系列專欄&#xff1a;&#x1f40d;《Python開源項目實戰》 &#x1f4a1; 熱愛不止于代碼&#xff0c;熱情…

JAVA房屋租售管理系統房屋出租出售平臺房屋銷售房屋租賃房屋交易信息管理源碼

一、源碼描述 這是一套房屋租售管理源碼&#xff0c;基于SpringBootVue框架&#xff0c;后端采用JAVA開發&#xff0c;源碼功能完善&#xff0c;涵蓋了房屋租賃、房屋銷售、房屋交易等業務。 二、源碼截圖

一篇文章講清楚mysql的聚簇索引、非聚簇索引、輔助索引

聚簇索引與非聚簇索引最大的區別就是&#xff1a; 聚簇索引的索引和數據是存放在一起的&#xff0c;都是在葉子結點&#xff1b; 非聚簇索引的索引和數據是分開存儲的&#xff0c;葉子節點存放的是索引和指向數據文件的地址&#xff0c;通過葉子節點找到索引&#xff0c;再通…

使用ESPHome燒錄固件到ESP32-C3并接入HomeAssistant

文章目錄 一、安裝ESPHome二、配置ESP32-C3控制燈1.主配置文件esp32c3-luat.yaml2.基礎通用配置base.yaml3.密碼文件secret.yaml4.圍欄燈four_light.yaml5.彩燈rgb_light.yaml6.左右柱燈left_right_light.yaml 三、安裝固件四、HomeAssistant配置ESPHome1.直接訪問2.配置ESPHom…

什么是變量提升?

變量提升&#xff08;Hoisting&#xff09; 是 JavaScript 引擎在代碼執行前的一個特殊行為&#xff0c;它會將變量聲明和函數聲明自動移動到當前作用域的頂部。但需要注意的是&#xff0c;只有聲明會被提升&#xff0c;賦值操作不會提升。 ??核心概念?? 變量聲明提升&…

【萬字長文】深入淺出 LlamaIndex 和 LangChain:從RAG到智能體,輕松駕馭LLM應用開發

Langchain系列文章目錄 01-玩轉LangChain&#xff1a;從模型調用到Prompt模板與輸出解析的完整指南 02-玩轉 LangChain Memory 模塊&#xff1a;四種記憶類型詳解及應用場景全覆蓋 03-全面掌握 LangChain&#xff1a;從核心鏈條構建到動態任務分配的實戰指南 04-玩轉 LangChai…