源程序代码
我们的 C# 程序中经常会产生一些数据,这些数据可以使用 Html 表格进行展现。现在让我们开始写相关的 C# 程序吧。下面就是 HtmlMaker.cs:
01: using System; 02: using System.IO; 03: using System.Net; 04: using System.Data; 05: using System.Drawing; 06: using System.Collections.Generic; 07: 08: namespace Skyiv 09: { 10: public sealed class HtmlMaker 11: { 12: public bool TitleVisible { get; set; } 13: 14: string title; 15: DataView view; 16: IEnumerable<Tuple<string, string>> info; 17: 18: public HtmlMaker(string title, IEnumerable<Tuple<string, string>> info, DataView view) 19: { 20: this.title = title; 21: this.info = info; 22: this.view = view; 23: this.TitleVisible = true; 24: } 25: 26: public void Save(string htmlFileName) 27: { 28: using (var writer = new StreamWriter(htmlFileName)) 29: { 30: WriteHead(writer); 31: WriteTitle(writer); 32: WriteInfo(writer); 33: new HtmlTable(view).Write(writer); 34: WriteTail(writer); 35: } 36: } 37: 38: void WriteTitle(TextWriter writer) 39: { 40: if (!TitleVisible) return; 41: writer.Write(" <h1>"); 42: WebUtility.HtmlEncode(title, writer); 43: writer.WriteLine("</h1>"); 44: } 45: 46: void WriteInfo(TextWriter writer) 47: { 48: if (info == null) return; 49: var dt = new DataTable(); 50: dt.Columns.Add("Key", typeof(string)); 51: dt.Columns.Add("Value", typeof(string)); 52: foreach (var row in info) 53: { 54: var dr = dt.NewRow(); 55: dr[0] = row.Item1; 56: dr[1] = row.Item2; 57: dt.Rows.Add(dr); 58: } 59: var htmlTable = new HtmlTable(dt.DefaultView); 60: htmlTable.ColumnHeadersVisible = false; 61: htmlTable.Write(writer); 62: } 63: 64: void WriteHead(TextWriter writer) 65: { 66: writer.Write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "); 67: writer.WriteLine("\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"); 68: writer.WriteLine("<html xmlns=\"http://www.w3.org/1999/xhtml\">"); 69: writer.WriteLine("<head>"); 70: writer.WriteLine(" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />"); 71: writer.Write(" <title>"); 72: WebUtility.HtmlEncode(title, writer); 73: writer.WriteLine("</title>"); 74: writer.WriteLine("</head>"); 75: writer.WriteLine("<body>"); 76: } 77: 78: void WriteTail(TextWriter writer) 79: { 80: writer.WriteLine("</body>"); 81: writer.WriteLine("</html>"); 82: } 83: } 84: }
注意上述程序第 70 行表明我们生成的 Html 文件是使用 UTF-8 编码,这应该成为一个共识。而在第 28 行使用的 StreamWriter 类默认情况也是使用 UTF8Encoding 。还有要注意第 42 行和第 72 行,在写入 Html 文件时要使用 WebUtility 类的静态方法 HtmlEncode 对数据进行编码。在第 33 行和第 59 行使用的 HtmlTable 类的源程序 HtmlTable.cs 如下所示:
01: using System; 02: using System.IO; 03: using System.Net; 04: using System.Data; 05: using System.Drawing; 06: 07: namespace Skyiv 08: { 09: sealed class HtmlTable 10: { 11: public int Level { get; set; } 12: public bool ColumnHeadersVisible { get; set; } 13: public Color ColumnHeadersBackgroundColor { get; set; } 14: public Color BackgroundColor { get; set; } 15: public Color AlternatingRowsBackgroundColor { get; set; } 16: 17: DataView view; 18: 19: public HtmlTable(DataView view) 20: { 21: this.view = view; 22: Level = 1; 23: ColumnHeadersVisible = true; 24: ColumnHeadersBackgroundColor = Color.Cyan; 25: BackgroundColor = Color.Azure; 26: AlternatingRowsBackgroundColor = Color.LightYellow; 27: } 28: 29: public void Write(TextWriter writer) 30: { 31: if (writer == null) return; 32: if (view == null) return; 33: var blank = "".PadLeft(Level * 2); 34: writer.Write(blank); 35: writer.Write("<table border=\"1\" cellspacing=\"2\" cellpadding=\"2\">"); 36: writer.Write("<tbody"); 37: WriteBackgroundColor(writer, BackgroundColor); 38: writer.WriteLine(">"); 39: if (ColumnHeadersVisible) WriteTableHead(writer); 40: var rowIndex = 0; 41: foreach (DataRowView row in view) WriteTableRow(writer, row, rowIndex++); 42: writer.Write(blank); 43: writer.WriteLine("</tbody></table>"); 44: } 45: 46: private void WriteBackgroundColor(TextWriter writer, Color color) 47: { 48: if (color == Color.Empty) return; 49: writer.Write(" style=\"background-color: "); 50: writer.Write(color.ToHtmlCode()); 51: writer.Write("\""); 52: } 53: 54: void WriteTableHead(TextWriter writer) 55: { 56: var blank2 = "".PadLeft((Level + 1) * 2); 57: var blank3 = "".PadLeft((Level + 2) * 2); 58: writer.Write(blank2); 59: writer.Write("<tr"); 60: WriteBackgroundColor(writer, ColumnHeadersBackgroundColor); 61: writer.WriteLine(">"); 62: foreach (DataColumn column in view.Table.Columns) 63: { 64: writer.Write(blank3); 65: writer.Write("<th>"); 66: WebUtility.HtmlEncode(column.Caption, writer); 67: writer.WriteLine("</th>"); 68: } 69: writer.Write(blank2); 70: writer.WriteLine("</tr>"); 71: } 72: 73: void WriteTableRow(TextWriter writer, DataRowView view, int rowIndex) 74: { 75: var blank2 = "".PadLeft((Level + 1) * 2); 76: var blank3 = "".PadLeft((Level + 2) * 2); 77: writer.Write(blank2); 78: writer.Write("<tr"); 79: if (rowIndex % 2 != 0) WriteBackgroundColor(writer, AlternatingRowsBackgroundColor); 80: writer.WriteLine(">"); 81: foreach (var field in view.Row.ItemArray) 82: { 83: writer.Write(blank3); 84: writer.Write("<td>"); 85: WebUtility.HtmlEncode(field.ToString(), writer); 86: writer.WriteLine("</td>"); 87: } 88: writer.Write(blank2); 89: writer.WriteLine("</tr>"); 90: } 91: } 92: }
几点说明:
- 第 11 行的 Level 字段表示这个 <table> 元素在 Html 文件中缩进层次,每缩进一层增加两个空格。
- 第 12 行的 ColumnHeadersVisible 字段表示是否要显示该表格的标题行。
- 第 13 行的 ColumnHeadersBackgroundColor 字段表示该表格标题行的背景色,默认值是青色(Cyan)。
- 第 14 行的 BackgroundColor 字段表示该表格的背景色,默认值是天蓝色(Azure)。
- 第 15 行的 AlternatingRowsBackgroundColor 字段表示该表格偶数行的背景色,默认值是浅黄色(LightYellow)。
- 以上三个字段的值都可以设为 Color.Empty,表示继承上一级的背景色。
- 第 50 行的 ToHtmlCode 方法是一个扩展方法,定义于 Skyiv.ExtensionMethods 静态类中。
下面就是 ExtensionMethods.cs:
01: using System.Drawing; 02: 03: namespace Skyiv 04: { 05: public static class ExtensionMethods 06: { 07: public static string ToHtmlCode(this Color color) 08: { 09: return string.Format("#{0:X2}{1:X2}{2:X2}", color.R, color.G, color.B); 10: } 11: } 12: }
使用示例
这让我们来看一个例子吧,下面就是 EnumTester.cs:
01: using System; 02: using System.Data; 03: using System.Collections.Generic; 04: 05: namespace Skyiv.Tester 06: { 07: sealed class EnumTester 08: { 09: static void Main() 10: { 11: try 12: { 13: var type = typeof(System.IO.FileAttributes); 14: var html = new HtmlMaker("枚举测试者", GetInfo(type), GetTable(type).DefaultView); 15: html.TitleVisible = false; 16: html.Save("enum.html"); 17: } 18: catch (Exception ex) 19: { 20: Console.Error.WriteLine(ex); 21: } 22: } 23: 24: static List<Tuple<string, string>> GetInfo(Type type) 25: { 26: var info = new List<Tuple<string, string>>(); 27: info.Add(Tuple.Create("枚举类型名称", type.ToString())); 28: info.Add(Tuple.Create("枚举成员数量", Enum.GetValues(type).Length.ToString())); 29: return info; 30: } 31: 32: static DataTable GetTable(Type type) 33: { 34: var table = new DataTable(); 35: table.Columns.Add("十进制", typeof(string)); 36: table.Columns.Add("十六进制", typeof(string)); 37: table.Columns.Add("名称", typeof(string)); 38: foreach (var v in Enum.GetValues(type)) 39: { 40: var dr = table.NewRow(); 41: dr[0] = Enum.Format(type, v, "D"); 42: dr[1] = Enum.Format(type, v, "X"); 43: dr[2] = Enum.Format(type, v, "G"); 44: table.Rows.Add(dr); 45: } 46: return table; 47: } 48: } 49: }
在 Windows Vista 操作系统的 .NET Fraemwork 4 环境中编译和运行:
E:\work> csc EnumTester.cs HtmlMaker.cs HtmlTable.cs ExtensionMethods.cs Microsoft(R) Visual C# 2010 编译器 4.0.30319.1 版 版权所有(C) Microsoft Corporation。保留所有权利。 E:\work> EnumTester E:\work>
这个 EnumTester.exe 运行后生成 enum.html 文件,在谷歌浏览器中的显示效果如下图所示:
这个 Html 文件的源代码如下所示:
01: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 02: <html xmlns="http://www.w3.org/1999/xhtml"> 03: <head> 04: <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 05: <title>枚举测试者</title> 06: </head> 07: <body> 08: <table border="1" cellspacing="2" cellpadding="2"><tbody style="background-color: #F0FFFF"> 09: <tr> 10: <td>枚举类型名称</td> 11: <td>System.IO.FileAttributes</td> 12: </tr> 13: <tr style="background-color: #FFFFE0"> 14: <td>枚举成员数量</td> 15: <td>14</td> 16: </tr> 17: </tbody></table> 18: <table border="1" cellspacing="2" cellpadding="2"><tbody style="background-color: #F0FFFF"> 19: <tr style="background-color: #00FFFF"> 20: <th>十进制</th> 21: <th>十六进制</th> 22: <th>名称</th> 23: </tr> 24: <tr> 25: <td>1</td> 26: <td>00000001</td> 27: <td>ReadOnly</td> 28: </tr> 29: <tr style="background-color: #FFFFE0"> 30: <td>2</td> 31: <td>00000002</td> 32: <td>Hidden</td> 33: </tr> 34: <tr> 35: <td>4</td> 36: <td>00000004</td> 37: <td>System</td> 38: </tr> 39: <tr style="background-color: #FFFFE0"> 40: <td>16</td> 41: <td>00000010</td> 42: <td>Directory</td> 43: </tr> 44: <tr> 45: <td>32</td> 46: <td>00000020</td> 47: <td>Archive</td> 48: </tr> 49: <tr style="background-color: #FFFFE0"> 50: <td>64</td> 51: <td>00000040</td> 52: <td>Device</td> 53: </tr> 54: <tr> 55: <td>128</td> 56: <td>00000080</td> 57: <td>Normal</td> 58: </tr> 59: <tr style="background-color: #FFFFE0"> 60: <td>256</td> 61: <td>00000100</td> 62: <td>Temporary</td> 63: </tr> 64: <tr> 65: <td>512</td> 66: <td>00000200</td> 67: <td>SparseFile</td> 68: </tr> 69: <tr style="background-color: #FFFFE0"> 70: <td>1024</td> 71: <td>00000400</td> 72: <td>ReparsePoint</td> 73: </tr> 74: <tr> 75: <td>2048</td> 76: <td>00000800</td> 77: <td>Compressed</td> 78: </tr> 79: <tr style="background-color: #FFFFE0"> 80: <td>4096</td> 81: <td>00001000</td> 82: <td>Offline</td> 83: </tr> 84: <tr> 85: <td>8192</td> 86: <td>00002000</td> 87: <td>NotContentIndexed</td> 88: </tr> 89: <tr style="background-color: #FFFFE0"> 90: <td>16384</td> 91: <td>00004000</td> 92: <td>Encrypted</td> 93: </tr> 94: </tbody></table> 95: </body> 96: </html>
符合 XHTML 1.0 Strict 规范
这个 Html 文件是符合 W3C 的 XHTML 1.0 Strict 规范的,如下图所示。
第二个使用示例
这让我们再看一个使用示例吧,下面就是 FileTester.cs:
01: using System; 02: using System.IO; 03: using System.Data; 04: using System.Collections.Generic; 05: 06: namespace Skyiv.Tester 07: { 08: sealed class FileTester 09: { 10: static void Main(string[] args) 11: { 12: try 13: { 14: var dir = new DirectoryInfo(args[0]); 15: var table = GetTable(dir); 16: var view = table.DefaultView; 17: view.Sort = "创建时间"; 18: view.RowFilter = "字节数 < 1024'"; 19: new HtmlMaker("文件测试者", GetInfo(dir, view), view).Save("file.html"); 20: } 21: catch (Exception ex) 22: { 23: Console.Error.WriteLine(ex); 24: } 25: } 26: 27: static List<Tuple<string, string>> GetInfo(DirectoryInfo dir, DataView view) 28: { 29: var info = new List<Tuple<string, string>>(); 30: info.Add(Tuple.Create("目录名称", dir.FullName)); 31: info.Add(Tuple.Create("筛选条件", view.RowFilter)); 32: return info; 33: } 34: 35: static DataTable GetTable(DirectoryInfo dir) 36: { 37: var table = new DataTable(); 38: table.Columns.Add("文件名", typeof(string)); 39: table.Columns.Add("特性", typeof(string)); 40: table.Columns.Add("创建时间", typeof(DateTime)); 41: table.Columns.Add("字节数", typeof(long)); 42: foreach (var file in dir.GetFiles()) 43: { 44: var dr = table.NewRow(); 45: dr[0] = file.Name; 46: dr[1] = file.Attributes; 47: dr[2] = file.CreationTime; 48: dr[3] = file.Length; 49: table.Rows.Add(dr); 50: } 51: return table; 52: } 53: } 54: }
几点说明:
- 第 17 行使用 DataView 类的 Sort 属性,使展现出来的文件按“创建时间”进行排序。
- 第 18 行使用 DataView 类的 RowFilter 属性,筛选出字节数小于 1024 的文件。
在 Windows Vista 操作系统的 .NET Framework 4 环境中编译和运行:
E:\work> csc FileTester.cs HtmlMaker.cs HtmlTable.cs ExtensionMethods.cs Microsoft(R) Visual C# 2010 编译器 4.0.30319.1 版 版权所有(C) Microsoft Corporation。保留所有权利。 E:\work> FileTester C:\Windows E:\work>
这次运行 FileTester.exe 程序时带命令行参数 C:\Windows ,生成 file.html 文件,在 IE8 浏览器中的显示效果如下图所示: