Read and Write Data is complete. Now let's take a look at how to generate the client interface. Using TabContainer of Atals is a good choice. Compare how to maintain the original format of cells, especially when cells are merged.
First, you must have a TabContainer control on the page, and then add the corresponding TabPanel according to the number of worksheets. You can add it as follows:
XmlNodeList sheet_node_list = xml. getElementsByTagName ("WORKSHEET"); for (int m = 0; m <sheet_node_list.Count; m ++) // traverses all worksheets {AjaxControlToolkit. tabPanel = null; // TabPanel control, where the table if (TabContainer1.Controls. count <m + 1) // TabContainer may contain TabPanel. Generally, after the TabContainer control is placed, one {panel = new AjaxControlToolkit is displayed. tabPanel (); // you need to add a new TabPanel TabContainer1.Controls. add (panel);} else panel = TabContainer1.Tabs [m]; // use an existing TabPanel. headerText = sheet_node_list [m]. attributes ["name"]. value; // set the TabPanel label to the worksheet name panel. ID = "Panel" + m; // set the ID panel. attributes. add ("Width", sheet_node_list [m]. attributes ["width"]. value); // obtain the table size. attributes. add ("Height", sheet_node_list [m]. attributes ["height"]. value); int _ rowNum = Math. max (1, int. parse (sheet_node_list [m]. attributes ["row"]. value) + 1); // obtain the maximum number of rows and columns in the Table. int _ colNum = Math. max (1, int. parse (sheet_node_list [m]. attributes ["col"]. value) + 1); // create table Table tbl = new Table (); // Our table always generates new drops of tbl. ID = panel. headerText + "_ Table"; // set the ID. The client ClintID will be in the format of ctrl_xxx_yy _ worksheet name_table. The JS script will use tbl. attributes. add ("activeCell", "null"); // currently active cell, used for JS script tbl. attributes. add ("cellspacing", "0"); // you can specify the table format tbl. attributes. add ("cellpadding", "0"); tbl. borderColor = System. drawing. color. aliceBlue; // Add a border tbl. borderStyle = BorderStyle. solid; tbl. borderWidth = 1; createTableHeader (tbl, _ rowNum, _ colNum); // create a header, simulate the column ID fillTableData (tbl, _ rowNum, _ colNum, sheet_node_list [m]); // fill in the cell data panel. controls. add (tbl); // Add the table to TabPanel}
The result shown in the browser is as follows:
Now let's take a look at the createTableHeader () method, which generates the header:
Protected void createTableHeader (Table tbl, int _ rowNum, int _ colNum) {bool isHeaderCell = false; // header flag // fill header for (int r = 0; r <_ rowNum; r ++) // traverse the row {TableRow row = new TableRow (); // generate the row for (int c = 0; c <_ colNum; c ++) // traverse the column {if (c = 0 | r = 0) {TableCell cell = new TableCell (); // generate the cell isHeaderCell = false; // initialize the cell flag. style. add ("border-left", "1px solid black"); // set the grid Cell. style. add ("border-top", "1px solid black"); cell. attributes. add ("width", "83pt"); // default width if (c = 0) // 0 column? {If (r = 0) // 0 rows? {Cell. text = ""; // fill in a space isHeaderCell = true; // set the flag} else {cell. text = r. toString (); // 0 columns start from the header of 1-N rows, and fill in the row number isHeaderCell = true; // set the flag if (r = _ rowNum-1) cell. style. add ("border-bottom", "1px solid black"); // draw the bottom line} else {if (r = 0) // N columns (N greater than 0) 0 rows, column header {cell. text = getColLetter (c-1); // generate the column ID isHeaderCell = true for the A-IV Based on the column number; // set the flag} if (isHeaderCell) // set the Header Format: center, silver color: Bottom {cell. attributes. add ("align", "center"); cell. style. add ("background-Color", "silver"); row. cells. add (cell); // Add a cell to the row object} row. style. add ("border", "1px solid black"); // sets the row border tbl. rows. add (row); // Add rows to columns }}
The method used to generate the A-IV type Excel column identification from the column number, as the homework, please complete it on your own.
After the header is generated, enter the following data:
Protected void fillTableData (Table tbl, int _ rowNum, int _ colNum, XmlNode sheet_node) {tbl. attributes. add ("cellpadding", "0"); // Add Table attributes tbl. attributes. add ("cellspacing", "0"); tbl. style. add ("border-collapse", "collapse"); // set the table style tbl. style. add ("table-layout", "fixed"); tbl. style. add ("width", sheet_node.Attributes ["width"]. value + "pt"); // The method for obtaining the worksheet size is described later in tbl. style. add ("border", "1px solid B Lack "); // black border foreach (XmlNode row_node in sheet_node.ChildNodes) // traverses the row {int rowIdx = int. parse (row_node.Attributes ["idx"]. value); // obtain the row number tbl. rows [rowIdx]. attributes. add ("height", row_node.Attributes ["height"]. value); // get the Row Height if (row_node.ChildNodes.Count = 0) // empty row? {For (int I = 1; I <= _ colNum-1; I ++) // Add an empty cell {tbl. rows [rowIdx]. cells. add (createEmptyCell () ;}} else foreach (XmlNode cell_node in row_node.ChildNodes) // traverses the row's cell {int coprocessor x = int. parse (cell_node.Attributes ["col"]. value); // The column number int colSpan = int. parse (cell_node.Attributes ["colspan"]. value); // the span of column merging int rowSpan = int. parse (cell_node.Attributes ["rowspan"]. value); // The span bool hasFormul of row Merging A = bool. Parse (cell_node.Attributes ["hasFormula"]. Value); // contains the formula? If (cell_node.previussibling! = Null) // is it the first cell with data? {// If two adjacent <CELL> elements are not consecutive, you must fill in the int prevco1_x = int. parse (cell_node.previussibling.attributes ["col"]. value), // The column number and column span of the previous cell prevColSpan = int. parse (cell_node.previussibling.attributes ["colspan"]. value); if (prevco1_x + prevColSpan <co1_x) // if there is a gap, fill in {for (int I = prevco1_x + prevColSpan; I <co1_x; I ++) {tbl. rows [rowIdx]. cells. add (createEmptyCell (); // Add an empty cell} else {if (co1_x> 1) // if the cell with data starting from is not the first column, you need to fill in the blank section {for (int I = 1; I <co1_x; I ++) {tbl. rows [rowIdx]. cells. add (createEmptyCell () ;}}// currently the play meat section. Add the cells with data {TableCell cell = new TableCell (); // set the font style cell. style. add ("font-family", cell_node.Attributes ["font-name"]. value); cell. style. add ("color", cell_node.Attributes ["font-color"]. value); cell. style. add ("font-size", cell_node.Attributes ["font-size"]. value ); Cell. style. add ("border", "1px solid black"); cell. style. add ("width", cell_node.Attributes ["width"]. value); // set the cell size. attributes. add ("width", cell_node.Attributes ["width"]. value); cell. attributes. add ("height", cell_node.Attributes ["height"]. value); // set the alignment mode cell. attributes. add ("align", cell_node.Attributes ["align"]. value); cell. attributes. add ("valign", cell_node.Attributes ["valign"]. value );// Set row and column spans // note: the rowspan attribute is not directly set, but the cell is handed over to the client script. attributes. add ("_ rowspan", cell_node.Attributes ["rowspan"]. value); cell. attributes. add ("colspan", cell_node.Attributes ["colspan"]. value); // Add the data domain cell. attributes. add ("hasFormula", cell_node.Attributes ["hasFormula"]. value); cell. attributes. add ("formula", cell_node.Attributes ["formula"]. value); cell. attributes. add ("dataField", hasFormula? Cell_node.Attributes ["formula"]. value: cell_node.Attributes ["value2"]. value); cell. attributes. add ("value2", cell_node.Attributes ["value2"]. value); // use value2 instead of value to avoid conflicts with HTML element attributes if (hasFormula) cell. attributes. add ("title", cell_node.Attributes ["formula"]. value); // The prompt when hovering is added. Here, it is only for the formula, or it can be a common cell. text = cell_node.Attributes ["value2"]. value; // sets the displayed text tbl. rows [rowIdx]. cells. add (cell); // Add to row} // if no subsequent
, Until the end of the column if (cell_node.NextSibling = null & codecomx + colSpan <_ colNum-1) {for (int I = codecomx + 1; I <= _ colNum-1; I ++) {tbl. rows [rowIdx]. cells. add (createEmptyCell () ;}}// for each cell} // for each row}
The following describes how to generate a blank cell:
Protected TableCell createEmptyCell () {TableCell cell = new TableCell (); cell. style. add ("border", "1px solid black"); // set the style cell. attributes. add ("hasFormula", "false"); // sets the data domain cell. attributes. add ("formula", ""); cell. attributes. add ("dataField", ""); cell. attributes. add ("value2", ""); cell. text = ""; // set the displayed Text return cell ;}
Now, table generation at runat = "server" has been completed, and the entire table has taken shape. Besides row span problems.
Use the following script to solve the row span problem. This section is titled "server-side generation". The client script should not be used. Here we only describe how the client implements the corresponding operations. Theoretically, the server can do a lot of work:
For (var I = tbl. cells. length-1; I> 1; I --) // traverse rows from the back to the front {var ctrl = tbl. cells [I]; // if (ctrl. cellIndex> 0 & ctrl. parentElement. rowIndex> 0) // 0 rows in the 0 column do not need to be processed {if (ctrl. _ rowspan & ctrl. _ rowspan> 1 & // span> 1 and the range does not exceed the table ctrl. parentElement. rowIndex + 1 <tbl. rows. length) {for (var n = 1; n <ctrl. _ rowspan; n ++) // merge cells {if (ctrl. cellIndex <tbl. rows [ctrl. parentElement. rowIndex + 1]. cells. length) // judge whether the tbl is exceeded once the merge is performed. rows [ctrl. parentElement. rowIndex + 1]. deleteCell (ctrl. cellIndex); // Delete the cells in the same column in the next row} ctrl. rowSpan = ctrl. _ rowspan; // The row span of the last cell }}}
Why do we need to traverse rows from the back to the front? When a cell is deleted, the subsequent cells are moved forward, which can be avoided in reverse order.