Word报告自动生成(例如 导出数据库结构)
? ? ? ? 將很早之前寫的一個(gè)小組件重新整理優(yōu)化一下,做成一個(gè)通用的功能。適用于導(dǎo)出數(shù)據(jù)庫的結(jié)構(gòu)(表、字段等)到Word或?qū)Ⅲw檢數(shù)據(jù)自動(dòng)生成Word版的體檢報(bào)告等。代碼:Github
一、主要需要完成功能:
1. 靈活的配置規(guī)則及word樣式設(shè)置(文本、表格、圖表、顏色等).
2. 支持表格.
3. 支持圖表.
4. 支持章節(jié)內(nèi)容循環(huán)生成.
5. 支持目錄.
6.支持文檔結(jié)構(gòu)圖
7.更新指定位置的文字
8.支持pdf導(dǎo)出.
?
最后結(jié)果如下:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖一
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖二
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? 圖三
二、需求分析與實(shí)現(xiàn)方式
? 功能主要涉及3個(gè)比較重要的部分:數(shù)據(jù)源、Word樣式、配置規(guī)則。?
? ?? 為了簡單,數(shù)據(jù)源決定采用一個(gè)存儲(chǔ)過程返回Dataset的方式, 整張報(bào)告的數(shù)據(jù)來源于此Dataset的多個(gè)Datatable.
樣式與配置:首先想到的是寫一個(gè)config文件,所有配置都放到一個(gè)文件里,然后將數(shù)據(jù)按照這個(gè)規(guī)則生成word。但無疑這樣的配置項(xiàng)太多了,關(guān)鍵是“樣式”問題,比如字體、顏色、表格寬度.....想想就頭大。而且沒有“所見即所得”的效果,配置完都不知道啥樣。
后來決定采取修改的方式, 先以一個(gè)word文件作為模板,在模板中定義好上面提到的“樣式”,然后在模板中做一個(gè)個(gè)標(biāo)記,然后將數(shù)據(jù)按照規(guī)則更新到對(duì)應(yīng)的標(biāo)記。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? 圖四
? ? 而這個(gè)標(biāo)記我們用到了word的一個(gè)叫【書簽】的功能,打開word按ctrl+shift+F5, 打開書簽功能,如下圖:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? 圖五
這樣將【規(guī)則】通過一系列規(guī)則的【書簽】定義到word模板中。
三、規(guī)則配置
思路確定了,那就開始設(shè)計(jì)如何通過【書簽】將規(guī)則定義到word模板中去,這里決定將所有規(guī)則都通過【書簽】實(shí)現(xiàn),而放棄config文件的方式,這個(gè)更統(tǒng)一而且直觀一些。
A.循環(huán)
? ? ? 以圖四為例,數(shù)據(jù)庫有多少張表是不固定的,我們在制作模板的時(shí)候不可能先畫好N(N為表的總數(shù))個(gè)表格等待數(shù)據(jù)填充, 這里就會(huì)需要遍歷數(shù)據(jù)源中提供的所有表結(jié)構(gòu)數(shù)據(jù),然后逐一形成表格。這里就需要將圖四中的表格循環(huán)一下,自動(dòng)復(fù)制生成多個(gè)這樣的表格。當(dāng)然,這只是一種情況,還有可能會(huì)出現(xiàn)循環(huán)嵌套循環(huán)的情況,那么我將這個(gè)循環(huán)定義成一個(gè)書簽的時(shí)候按照這樣的格式:
? ? ? loop_級(jí)別_表序號(hào)_filter_名稱
含義如下:
? ?? loop:代表這是一個(gè)循環(huán)。
? ?? 級(jí)別:默認(rèn)文檔級(jí)別為0,出現(xiàn)的第一層循環(huán)為1,其內(nèi)部若再次嵌套循環(huán)則級(jí)別為2,依次類推。
? ?? 表序號(hào):取Dataset中的第幾張表(從1開始)
? ?? filter:循環(huán)的時(shí)候可能會(huì)用到對(duì)datatable的查找過濾,在此寫出,多個(gè)字段用XX隔開(因?yàn)榇颂幉辉试S有下劃線外其他特殊字符, 就用這個(gè)XX吧 )
? ?? 名稱:loop名稱,方便與其他 loop區(qū)別
?B.更新指定位置的文字
? ? 如圖四中的【服務(wù)器名】、【表總數(shù)】等,只需要替換對(duì)應(yīng)的文字即可:
? ? label_級(jí)別_名稱
含義如下:
? ?? label:代表這是一個(gè)label。
? ?? 級(jí)別:默認(rèn)文檔級(jí)別為0,出現(xiàn)的第一層循環(huán)為1,其內(nèi)部若再次嵌套循環(huán)則級(jí)別為2,依次類推。
? ?? 名稱:label名稱
? ?? 注意這里省略了表序號(hào),當(dāng)級(jí)別為0的時(shí)候 ,自動(dòng)取最后一個(gè)datatable中的數(shù)據(jù),因?yàn)檫@個(gè)label經(jīng)常會(huì)用到其他表匯總的數(shù)據(jù),可能會(huì)用到之前幾張表的數(shù)據(jù),所以放在其他表都處理好后。當(dāng)級(jí)別為1的時(shí)候,自然取該級(jí)別循環(huán)的行數(shù)據(jù)。
C.表格
? ?? 表格的配置原本也想對(duì)表格添加書簽,后來發(fā)現(xiàn)有個(gè)表格屬性, 覺得寫在這里更好一些。
?如上圖所示,【標(biāo)題】格式為:table_級(jí)別_取Dataset中的第幾張表(從1開始)_filter字段多個(gè)用XX隔開(此處不允許有下劃線外其他特殊字符, 就用這個(gè)XX吧 )_名稱
【說明】為可選項(xiàng),若需要合計(jì)行, 則需要標(biāo)識(shí),?summary或縮寫s: [合計(jì)]行是模板中表格的第幾行 ??summaryfilter或縮寫sf:數(shù)據(jù)集進(jìn)一步filter到summary行的條件(因?yàn)橐粋€(gè)表格只取一個(gè)Datatable,通過一個(gè)標(biāo)識(shí)指定了哪些datarow是用來作為合計(jì)的)
D.圖表
同樣為了方便將配置寫在了【標(biāo)題】,圖表生成后會(huì)將名稱修改過來。
配置格式為:chart_級(jí)別_取Dataset中的第幾張表(從1開始)_filter字段多個(gè)用XX隔開(此處不允許有下劃線外其他特殊字符, 就用這個(gè)XX吧 )_chart名稱_是否將Datatable的columnName作為第一行_從datatable第幾列開始(列起始為1)_截止列,
如下圖所示配置即可。
?
E.目錄
無需標(biāo)識(shí), 模板中添加目錄, 當(dāng)內(nèi)容處理完成之后, 會(huì)根據(jù)處理后的結(jié)果動(dòng)態(tài)更新目錄.
?
四、主要代碼
1 using System; 2 using System.Collections.Generic; 3 using System.Data; 4 using System.Diagnostics; 5 using System.IO; 6 using System.Linq; 7 using System.Reflection; 8 using Excel = Microsoft.Office.Interop.Excel; 9 using Word = Microsoft.Office.Interop.Word; 10 11 namespace FlyLolo.WordReport.Demo 12 { 13 public class WordReportHelper 14 { 15 private Word.Application wordApp = null; 16 private Word.Document wordDoc = null; 17 private DataSet dataSource = null; 18 private object line = Word.WdUnits.wdLine; 19 private string errorMsg = ""; 20 21 /// <summary> 22 /// 根據(jù)模板文件,創(chuàng)建數(shù)據(jù)報(bào)告 23 /// </summary> 24 /// <param name="templateFile">模板文件名(含路徑)</param> 25 /// <param name="newFilePath">新文件路徑)</param> 26 /// <param name="dataSource">數(shù)據(jù)源,包含多個(gè)datatable</param> 27 /// <param name="saveFormat">新文件格式:</param> 28 public bool CreateReport(string templateFile, DataSet dataSource, out string errorMsg, string newFilePath, ref string newFileName, int saveFormat = 16) 29 { 30 this.dataSource = dataSource; 31 errorMsg = this.errorMsg; 32 bool rtn = OpenTemplate(templateFile) 33 && SetContent(new WordElement(wordDoc.Range(), dataRow: dataSource.Tables[dataSource.Tables.Count - 1].Rows[0])) 34 && UpdateTablesOfContents() 35 && SaveFile(newFilePath, ref newFileName, saveFormat); 36 37 CloseAndClear(); 38 return rtn; 39 } 40 41 /// <summary> 42 /// 打開模板文件 43 /// </summary> 44 /// <param name="templateFile"></param> 45 /// <returns></returns> 46 private bool OpenTemplate(string templateFile) 47 { 48 if (!File.Exists(templateFile)) 49 { 50 return false; 51 } 52 53 wordApp = new Word.Application(); 54 wordApp.Visible = true;//使文檔可見,調(diào)試用 55 wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone; 56 object file = templateFile; 57 wordDoc = wordApp.Documents.Open(ref file, ReadOnly: false); 58 return true; 59 } 60 61 /// <summary> 62 /// 為指定區(qū)域?qū)懭霐?shù)據(jù) 63 /// </summary> 64 /// <param name="element"></param> 65 /// <returns></returns> 66 private bool SetContent(WordElement element) 67 { 68 string currBookMarkName = string.Empty; 69 string startWith = "loop_" + (element.Level + 1).ToString() + "_"; 70 foreach (Word.Bookmark item in element.Range.Bookmarks) 71 { 72 currBookMarkName = item.Name; 73 74 if (currBookMarkName.StartsWith(startWith) && (!currBookMarkName.Equals(element.ElementName))) 75 { 76 SetLoop(new WordElement(item.Range, currBookMarkName, element.DataRow, element.GroupBy)); 77 } 78 79 } 80 81 SetLabel(element); 82 83 SetTable(element); 84 85 SetChart(element); 86 87 return true; 88 } 89 90 /// <summary> 91 /// 處理循環(huán) 92 /// </summary> 93 /// <param name="element"></param> 94 /// <returns></returns> 95 private bool SetLoop(WordElement element) 96 { 97 DataRow[] dataRows = dataSource.Tables[element.TableIndex].Select(element.GroupByString); 98 int count = dataRows.Count(); 99 element.Range.Select(); 100 101 //第0行作為模板 先從1開始 循環(huán)后處理0行; 102 for (int i = 0; i < count; i++) 103 { 104 105 element.Range.Copy(); //模板loop復(fù)制 106 wordApp.Selection.InsertParagraphAfter();//換行 不會(huì)清除選中的內(nèi)容,TypeParagraph 等同于回車,若當(dāng)前有選中內(nèi)容會(huì)被清除. TypeParagraph 會(huì)跳到下一行,InsertParagraphAfter不會(huì), 所以movedown一下. 107 wordApp.Selection.MoveDown(ref line, Missing.Value, Missing.Value); 108 wordApp.Selection.Paste(); //換行后粘貼復(fù)制內(nèi)容 109 int offset = wordApp.Selection.Range.End - element.Range.End; //計(jì)算偏移量 110 111 //復(fù)制書簽,書簽名 = 模板書簽名 + 復(fù)制次數(shù) 112 foreach (Word.Bookmark subBook in element.Range.Bookmarks) 113 { 114 if (subBook.Name.Equals(element.ElementName)) 115 { 116 continue; 117 } 118 119 wordApp.Selection.Bookmarks.Add(subBook.Name + "_" + i.ToString(), wordDoc.Range(subBook.Start + offset, subBook.End + offset)); 120 } 121 122 SetContent(new WordElement(wordDoc.Range(wordApp.Selection.Range.End - (element.Range.End - element.Range.Start), wordApp.Selection.Range.End), element.ElementName + "_" + i.ToString(), dataRows[i], element.GroupBy)); 123 } 124 125 element.Range.Delete(); 126 127 return true; 128 } 129 130 /// <summary> 131 /// 處理簡單Label 132 /// </summary> 133 /// <param name="element"></param> 134 /// <returns></returns> 135 private bool SetLabel(WordElement element) 136 { 137 if (element.Range.Bookmarks != null && element.Range.Bookmarks.Count > 0) 138 { 139 string startWith = "label_" + element.Level.ToString() + "_"; 140 string bookMarkName = string.Empty; 141 foreach (Word.Bookmark item in element.Range.Bookmarks) 142 { 143 bookMarkName = item.Name; 144 145 if (bookMarkName.StartsWith(startWith)) 146 { 147 bookMarkName = WordElement.GetName(bookMarkName); 148 149 item.Range.Text = element.DataRow[bookMarkName].ToString(); 150 } 151 } 152 } 153 154 return true; 155 } 156 157 /// <summary> 158 /// 填充Table 159 /// </summary> 160 /// <param name="element"></param> 161 /// <returns></returns> 162 private bool SetTable(WordElement element) 163 { 164 if (element.Range.Tables != null && element.Range.Tables.Count > 0) 165 { 166 string startWith = "table_" + element.Level.ToString() + "_"; 167 foreach (Word.Table table in element.Range.Tables) 168 { 169 if (!string.IsNullOrEmpty(table.Title) && table.Title.StartsWith(startWith)) 170 { 171 WordElement tableElement = new WordElement(null, table.Title, element.DataRow); 172 173 TableConfig config = new TableConfig(table.Descr); 174 175 object dataRowTemplate = table.Rows[config.DataRow]; 176 Word.Row SummaryRow = null; 177 DataRow SummaryDataRow = null; 178 DataTable dt = dataSource.Tables[tableElement.TableIndex]; 179 DataRow[] dataRows = dataSource.Tables[tableElement.TableIndex].Select(tableElement.GroupByString); ; 180 181 if (config.SummaryRow > 0) 182 { 183 SummaryRow = table.Rows[config.SummaryRow]; 184 SummaryDataRow = dt.Select(string.IsNullOrEmpty(tableElement.GroupByString) ? config.SummaryFilter : tableElement.GroupByString + " and " + config.SummaryFilter).FirstOrDefault(); 185 } 186 187 foreach (DataRow row in dataRows) 188 { 189 if (row == SummaryDataRow) 190 { 191 continue; 192 } 193 194 Word.Row newRow = table.Rows.Add(ref dataRowTemplate); 195 for (int j = 0; j < table.Columns.Count; j++) 196 { 197 newRow.Cells[j + 1].Range.Text = row[j].ToString(); ; 198 } 199 200 } 201 202 ((Word.Row)dataRowTemplate).Delete(); 203 204 if (config.SummaryRow > 0 && SummaryDataRow != null) 205 { 206 for (int j = 0; j < SummaryRow.Cells.Count; j++) 207 { 208 string temp = SummaryRow.Cells[j + 1].Range.Text.Trim().Replace("\r\a", ""); 209 210 if (!string.IsNullOrEmpty(temp) && temp.Length > 2 && dt.Columns.Contains(temp.Substring(1, temp.Length - 2))) 211 { 212 SummaryRow.Cells[j + 1].Range.Text = SummaryDataRow[temp.Substring(1, temp.Length - 2)].ToString(); 213 } 214 } 215 } 216 217 table.Title = tableElement.Name; 218 } 219 220 221 } 222 } 223 224 return true; 225 } 226 227 /// <summary> 228 /// 處理圖表 229 /// </summary> 230 /// <param name="element"></param> 231 /// <returns></returns> 232 private bool SetChart(WordElement element) 233 { 234 if (element.Range.InlineShapes != null && element.Range.InlineShapes.Count > 0) 235 { 236 List<Word.InlineShape> chartList = element.Range.InlineShapes.Cast<Word.InlineShape>().Where(m => m.Type == Word.WdInlineShapeType.wdInlineShapeChart).ToList(); 237 string startWith = "chart_" + element.Level.ToString() + "_"; 238 foreach (Word.InlineShape item in chartList) 239 { 240 Word.Chart chart = item.Chart; 241 if (!string.IsNullOrEmpty(chart.ChartTitle.Text) && chart.ChartTitle.Text.StartsWith(startWith)) 242 { 243 WordElement chartElement = new WordElement(null, chart.ChartTitle.Text, element.DataRow); 244 245 DataTable dataTable = dataSource.Tables[chartElement.TableIndex]; 246 DataRow[] dataRows = dataTable.Select(chartElement.GroupByString); 247 248 int columnCount = dataTable.Columns.Count; 249 List<int> columns = new List<int>(); 250 251 foreach (var dr in dataRows) 252 { 253 for (int i = chartElement.ColumnStart == -1 ? 0 : chartElement.ColumnStart - 1; i < (chartElement.ColumnEnd == -1 ? columnCount : chartElement.ColumnEnd); i++) 254 { 255 if (columns.Contains(i) || dr[i] == null || string.IsNullOrEmpty(dr[i].ToString())) 256 { 257 258 } 259 else 260 { 261 columns.Add(i); 262 } 263 } 264 } 265 columns.Sort(); 266 columnCount = columns.Count; 267 int rowsCount = dataRows.Length; 268 269 Word.ChartData chartData = chart.ChartData; 270 271 //chartData.Activate(); 272 //此處有個(gè)比較疑惑的問題, 不執(zhí)行此條,生成的報(bào)告中的圖表無法再次右鍵編輯數(shù)據(jù). 執(zhí)行后可以, 但有兩個(gè)問題就是第一會(huì)彈出Excel框, 處理完后會(huì)自動(dòng)關(guān)閉. 第二部分chart的數(shù)據(jù)range設(shè)置總不對(duì) 273 //不知道是不是版本的問題, 誰解決了分享一下,謝謝 274 275 Excel.Workbook dataWorkbook = (Excel.Workbook)chartData.Workbook; 276 dataWorkbook.Application.Visible = false; 277 278 Excel.Worksheet dataSheet = (Excel.Worksheet)dataWorkbook.Worksheets[1]; 279 //設(shè)定范圍 280 string a = (chartElement.ColumnNameForHead ? rowsCount + 1 : rowsCount) + "|" + columnCount; 281 Console.WriteLine(a); 282 283 Excel.Range tRange = dataSheet.Range["A1", dataSheet.Cells[(chartElement.ColumnNameForHead ? rowsCount + 1 : rowsCount), columnCount]]; 284 Excel.ListObject tbl1 = dataSheet.ListObjects[1]; 285 //dataSheet.ListObjects[1].Delete(); //想過重新刪除再添加 這樣 原有數(shù)據(jù)清掉了, 但覺得性能應(yīng)該會(huì)有所下降 286 //Excel.ListObject tbl1 = dataSheet.ListObjects.AddEx(); 287 tbl1.Resize(tRange); 288 for (int j = 0; j < rowsCount; j++) 289 { 290 DataRow row = dataRows[j]; 291 for (int k = 0; k < columnCount; k++) 292 { 293 dataSheet.Cells[j + 2, k + 1].FormulaR1C1 = row[columns[k]]; 294 } 295 } 296 297 if (chartElement.ColumnNameForHead) 298 { 299 for (int k = 0; k < columns.Count; k++) 300 { 301 dataSheet.Cells[1, k + 1].FormulaR1C1 = dataTable.Columns[columns[k]].ColumnName; 302 } 303 } 304 chart.ChartTitle.Text = chartElement.Name; 305 //dataSheet.Application.Quit(); 306 } 307 } 308 } 309 310 return true; 311 } 312 313 /// <summary> 314 /// 更新目錄 315 /// </summary> 316 /// <returns></returns> 317 private bool UpdateTablesOfContents() 318 { 319 foreach (Word.TableOfContents item in wordDoc.TablesOfContents) 320 { 321 item.Update(); 322 } 323 324 return true; 325 } 326 327 /// <summary> 328 /// 保存文件 329 /// </summary> 330 /// <param name="newFilePath"></param> 331 /// <param name="newFileName"></param> 332 /// <param name="saveFormat"></param> 333 /// <returns></returns> 334 private bool SaveFile(string newFilePath, ref string newFileName, int saveFormat = 16) 335 { 336 if (string.IsNullOrEmpty(newFileName)) 337 { 338 newFileName = DateTime.Now.ToString("yyyyMMddHHmmss"); 339 340 switch (saveFormat) 341 { 342 case 0:// Word.WdSaveFormat.wdFormatDocument 343 newFileName += ".doc"; 344 break; 345 case 16:// Word.WdSaveFormat.wdFormatDocumentDefault 346 newFileName += ".docx"; 347 break; 348 case 17:// Word.WdSaveFormat.wdFormatPDF 349 newFileName += ".pdf"; 350 break; 351 default: 352 break; 353 } 354 } 355 356 object newfile = Path.Combine(newFilePath, newFileName); 357 object wdSaveFormat = saveFormat; 358 wordDoc.SaveAs(ref newfile, ref wdSaveFormat); 359 return true; 360 } 361 362 /// <summary> 363 /// 清理 364 /// </summary> 365 private void CloseAndClear() 366 { 367 if (wordApp == null) 368 { 369 return; 370 } 371 wordDoc.Close(Word.WdSaveOptions.wdDoNotSaveChanges); 372 wordApp.Quit(Word.WdSaveOptions.wdDoNotSaveChanges); 373 System.Runtime.InteropServices.Marshal.ReleaseComObject(wordDoc); 374 System.Runtime.InteropServices.Marshal.ReleaseComObject(wordApp); 375 wordDoc = null; 376 wordApp = null; 377 GC.Collect(); 378 KillProcess("Excel", "WINWORD"); 379 } 380 381 /// <summary> 382 /// 殺進(jìn)程.. 383 /// </summary> 384 /// <param name="processNames"></param> 385 private void KillProcess(params string[] processNames) 386 { 387 //Process myproc = new Process(); 388 //得到所有打開的進(jìn)程 389 try 390 { 391 foreach (string name in processNames) 392 { 393 foreach (Process thisproc in Process.GetProcessesByName(name)) 394 { 395 if (!thisproc.CloseMainWindow()) 396 { 397 if (thisproc != null) 398 thisproc.Kill(); 399 } 400 } 401 } 402 } 403 catch (Exception) 404 { 405 //throw Exc; 406 // msg.Text+= "殺死" + processName + "失敗!"; 407 } 408 } 409 } 410 411 /// <summary> 412 /// 封裝的Word元素 413 /// </summary> 414 public class WordElement 415 { 416 public WordElement(Word.Range range, string elementName = "", DataRow dataRow = null, Dictionary<string, string> groupBy = null, int tableIndex = 0) 417 { 418 this.Range = range; 419 this.ElementName = elementName; 420 this.GroupBy = groupBy; 421 this.DataRow = dataRow; 422 if (string.IsNullOrEmpty(elementName)) 423 { 424 this.Level = 0; 425 this.TableIndex = tableIndex; 426 this.Name = string.Empty; 427 this.ColumnNameForHead = false; 428 } 429 else 430 { 431 string[] element = elementName.Split('_'); 432 this.Level = int.Parse(element[1]); 433 this.ColumnNameForHead = false; 434 this.ColumnStart = -1; 435 this.ColumnEnd = -1; 436 437 if (element[0].Equals("label")) 438 { 439 this.Name = element[2]; 440 this.TableIndex = 0; 441 } 442 else 443 { 444 this.Name = element[4]; 445 this.TableIndex = int.Parse(element[2]) - 1; 446 447 if (!string.IsNullOrEmpty(element[3])) 448 { 449 string[] filters = element[3].Split(new string[] { "XX" }, StringSplitOptions.RemoveEmptyEntries); 450 if (this.GroupBy == null) 451 { 452 this.GroupBy = new Dictionary<string, string>(); 453 } 454 foreach (string item in filters) 455 { 456 if (!this.GroupBy.Keys.Contains(item)) 457 { 458 this.GroupBy.Add(item, dataRow[item].ToString()); 459 } 460 461 } 462 } 463 464 if (element[0].Equals("chart") && element.Count() > 5) 465 { 466 this.ColumnNameForHead = element[5].Equals("1"); 467 this.ColumnStart = string.IsNullOrEmpty(element[6]) ? -1 : int.Parse(element[6]); 468 this.ColumnEnd = string.IsNullOrEmpty(element[7]) ? -1 : int.Parse(element[7]); 469 } 470 } 471 } 472 } 473 474 public Word.Range Range { get; set; } 475 public int Level { get; set; } 476 public int TableIndex { get; set; } 477 public string ElementName { get; set; } 478 479 public DataRow DataRow { get; set; } 480 public Dictionary<string, string> GroupBy { get; set; } 481 482 public string Name { get; set; } 483 484 public bool ColumnNameForHead { get; set; } 485 public int ColumnStart { get; set; } 486 public int ColumnEnd { get; set; } 487 488 public string GroupByString 489 { 490 get 491 { 492 if (GroupBy == null || GroupBy.Count == 0) 493 { 494 return string.Empty; 495 } 496 497 string rtn = string.Empty; 498 foreach (string key in this.GroupBy.Keys) 499 { 500 rtn += "and " + key + " = '" + GroupBy[key] + "' "; 501 } 502 return rtn.Substring(3); 503 } 504 } 505 506 public static string GetName(string elementName) 507 { 508 string[] element = elementName.Split('_'); 509 510 511 if (element[0].Equals("label")) 512 { 513 return element[2]; 514 } 515 else 516 { 517 return element[4]; 518 } 519 } 520 } 521 522 /// <summary> 523 /// Table配置項(xiàng) 524 /// </summary> 525 public class TableConfig 526 { 527 public TableConfig(string tableDescr = "") 528 { 529 this.DataRow = 2; 530 this.SummaryRow = -1; 531 532 if (!string.IsNullOrEmpty(tableDescr)) 533 { 534 string[] element = tableDescr.Split(','); 535 foreach (string item in element) 536 { 537 if (!string.IsNullOrEmpty(item)) 538 { 539 string[] configs = item.Split(':'); 540 if (configs.Length == 2) 541 { 542 switch (configs[0].ToLower()) 543 { 544 case "data": 545 case "d": 546 this.DataRow = int.Parse(configs[1]); 547 break; 548 case "summary": 549 case "s": 550 this.SummaryRow = int.Parse(configs[1]); 551 break; 552 case "summaryfilter": 553 case "sf": 554 this.SummaryFilter = configs[1]; 555 break; 556 default: 557 break; 558 } 559 } 560 } 561 } 562 } 563 564 } 565 public int DataRow { get; set; } 566 public int SummaryRow { get; set; } 567 public string SummaryFilter { get; set; } 568 } 569 } View Code?
轉(zhuǎn)載于:https://www.cnblogs.com/FlyLolo/p/WordReport.html
總結(jié)
以上是生活随笔為你收集整理的Word报告自动生成(例如 导出数据库结构)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 好用的安卓版通话录音软件推荐?
- 下一篇: 一个手机怎么设置两个密码?