使用 GridView.RenderControl() 導出 Word 時,模板列中的 TextBox 控件被渲染為 HTML ``,導出文檔中顯示為輸入框而非純文本。
RenderControl 會递归渲染控件樹的完整 HTML,包含輸入控件的標簽結構。Word 打開 HTML 時解析為表單字段。
| 方案 | 原理 | 優點 | 缺點 |
|---|---|---|---|
| 方案一:導出前替換控件為 Literal/Lable (推薦) | 在導出邏輯中遍歷 GridView 行,將 TextBox 替換為只顯示文本的 Literal 控件 | 保持 GridView 結構、樣式完整、代碼可控、無需第三方庫 | 需臨時修改控件樹,導出後恢復 |
| 方案二:使用第三方庫 (NPOI / Open XML SDK / Aspose.Words) | 程序化創建真實 .docx 文件,精確控制單元格內容 | 生成原生 Word 格式、功能強大(表格樣式、圖片、分頁)、不依賴 HTML 渲染 | 引入依賴、學習成本、Aspose 收費 |
| 方案三:CSS 隱藏輸入框邊框/背景 | 導出 HTML 中包含 style="border:none;background:transparent;" |
最簡單,僅加一行 CSS | Word 可能仍識別為表單字段、複製粘貼帶標簽、不純粹 |
| 方案四:保存為服務器臨時文件再下載 (原回答思路) | 服務端用 Word 自動化/組件生成 .doc 保存,再提供下載 | 可預覽、留存歸檔 | 服務端需安裝 Office/組件、佔用資源、併發差、不推薦 Web 服務器 |
protected void btnExportWord_Click(object sender, EventArgs e) {
// 1. 保存原始控件引用以便恢復 (若頁面需繼續編輯)
// 實際上導出後通常 Redirect 或結束響應,無需恢復
// 2. 遍歷行,將 TextBox 替換為 Label 顯示純文本
foreach (GridViewRow row in GridView1.Rows) {
if (row.RowType == DataControlRowType.DataRow) {
// 假設第 2 列是模板列包含 TextBox
TextBox txt = row.FindControl("txtName") as TextBox; // 你的 TextBox ID
if (txt != null) {
Label lbl = new Label();
lbl.Text = txt.Text;
lbl.CssClass = txt.CssClass; // 保留樣式類
// 替換控件
int cellIndex = 1; // 列索引
TableCell cell = row.Cells[cellIndex];
cell.Controls.Clear();
cell.Controls.Add(lbl);
}
}
}
// 3. 導出邏輯 (原代碼基本不變)
Response.Clear();
Response.Buffer = true;
Response.Charset = "UTF-8";
Response.AppendHeader("Content-Disposition", "attachment;filename=Export.doc");
Response.ContentEncoding = System.Text.Encoding.GetEncoding("UTF-8");
Response.ContentType = "application/ms-word";
EnableViewState = false;
using (StringWriter sw = new StringWriter())
using (HtmlTextWriter hw = new HtmlTextWriter(sw)) {
GridView1.RenderControl(hw);
Response.Output.Write(sw.ToString());
}
Response.Flush();
Response.End();
}
// 必須重寫 VerifyRenderingInServerForm 允許 GridView 在非表單中渲染
public override void VerifyRenderingInServerForm(Control control) { }
// NuGet: Install-Package NPOI
protected void btnExportExcel_Click(object sender, EventArgs e) {
IWorkbook workbook = new XSSFWorkbook(); // .xlsx
ISheet sheet = workbook.CreateSheet("數據");
// 標題行
IRow headerRow = sheet.CreateRow(0);
for (int i = 0; i < GridView1.Columns.Count; i++) {
headerRow.CreateCell(i).SetCellValue(GridView1.Columns[i].HeaderText);
}
// 數據行
for (int r = 0; r < GridView1.Rows.Count; r++) {
GridViewRow gvRow = GridView1.Rows[r];
if (gvRow.RowType != DataControlRowType.DataRow) continue;
IRow dataRow = sheet.CreateRow(r + 1);
for (int c = 0; c < GridView1.Columns.Count; c++) {
string cellText = "";
// 獲取純文本:優先找控件 Text,否則取單元格文本
Control ctrl = gvRow.Cells[c].Controls[0]; // 簡化,實際需遞歸查找
if (ctrl is TextBox) cellText = ((TextBox)ctrl).Text;
else if (ctrl is Label) cellText = ((Label)ctrl).Text;
else cellText = gvRow.Cells[c].Text; // 可能包含
dataRow.CreateCell(c).SetCellValue(cellText.Trim());
}
}
// 自適應列寬
for (int i = 0; i < GridView1.Columns.Count; i++) sheet.AutoSizeColumn(i);
// 輸出
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AppendHeader("Content-Disposition", "attachment;filename=Export.xlsx");
using (MemoryStream ms = new MemoryStream()) {
workbook.Write(ms);
Response.BinaryWrite(ms.ToArray());
}
Response.End();
}