<file_sep>﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Diagnostics;

namespace GradeDiagramTest
{
    public partial class GradeDiagramPlot : System.Web.UI.Page
    {
        // Student Scroe and Question from Database
        
        
        public string []FirstColDefault = {"學生","總分"};
       

        //
       
        List<ScoreAnalysisM> ScoreAnalysisList = new List<ScoreAnalysisM>();
        private int table_rows;
        private int table_cols;

        private List<int[]> QuestionAvg=new List<int[]>();
        private List<string> correctXML = new List<string>();
        private int MemberQuestionNum;
        private int studentNum;
        private int currentQuestion=0;
        private List<string> AddRowsName = new List<string>();
        private List<string> AddColsName = new List<string>();
        public string[] QuestionName;
        public List<string[]> MemberQuestionAnswer=new List<string[]>();
        private Hashtable[] correctAnswerHT ;

        protected void Page_Load(object sender, EventArgs e)
        {

            

            //下方3個變數的值之後會由DB取得
            //get all the data from IPCExamHWCorrectAnswer table



            string cActivityID_Selector = Request.QueryString["cActivityID"];
            DataTable dt = CsDBOp.GetAllTBData("IPCExamHWCorrectAnswer", cActivityID_Selector);
            //Exception for empty table data
            if (dt.Rows.Count==0)
                Response.End();


            //Test for cActivityID with input for IPCExamHWCorrectAnswer
            QuestionName=dt.Rows[0].Field<string>("QuestionBodyPart").Split(',');
            string TempCA=dt.Rows[0].Field<string>("correctAnswer");
            foreach (string TempCA_fullstr in TempCA.Remove(TempCA.Length - 1).Split(':'))
            {
                 
                 MemberQuestionAnswer.Add(TempCA_fullstr.Split(','));
            }

            string temp_str= dt.Rows[0].Field<string>("correctAnswerOrdering");
            string[] tempCAOstr = temp_str.Remove(temp_str.Length-1).Split(':');
            correctAnswerHT = new Hashtable[tempCAOstr.Length];
            int index = 0;
            foreach (string tempCAOstr_split in tempCAOstr)
            {
                string[] tempCAOstr_in_split = tempCAOstr_split.Split(',');
                correctXML.Add(tempCAOstr_in_split[0]);
                correctAnswerHT[index] = new Hashtable();
                for (int i = 1; i < tempCAOstr_in_split.Length; i++)
                {
                    correctAnswerHT[index].Add(tempCAOstr_in_split[i], MemberQuestionAnswer[index][i]);
                }
                index++;
            }


            dt = CsDBOp.GetAllTBData("StuCouHWDe_IPC", cActivityID_Selector);

            //Get the retrieved data from each row of the retrieved data table.
            foreach (DataRow dr in dt.Rows)
            {
                string StudentIDTemp = dr.Field<string>("StuCouHWDe_ID");
                string Gradetemp = dr.Field<string>("Grade");
                if (Gradetemp != null)
                {
                    ScoreAnalysisM log_temp = new ScoreAnalysisM(StudentIDTemp, Gradetemp);
                    ScoreAnalysisList.Add(log_temp);
                    continue;
                }
                    
                
                string AnsewerTemp = dr.Field<string>("StudentAnswer");
                string QuesOrdering = dr.Field<string>("QuesOrdering");
                if (AnsewerTemp == null)
                    continue;
                ScoreAnalysisM log = new ScoreAnalysisM(StudentIDTemp, AnsewerTemp, QuesOrdering,correctXML,correctAnswerHT);
                ScoreAnalysisList.Add(log);

                //比對學生作答內容中的XML檔名
                if (log.XMLerror)
                {
                    Response.Write("alert('Student answer XML file name does not match Correct answer XML file name')");
                    Response.End();
                }

            }
            
            
            //// Add a row named Avg
            AddRow("Avg");
            
            //// calculate average
            MemberQueAvgCal();

            // Add table html for front-end dynamically
            AddDynamicTableHtml(QuestionName.Length, QuestionName);
            

            /// plot the chart
            tab_content_chart_control.InnerHtml = AddChartTabPaneHtml();

            
        }

        private string AddChartTabPaneHtml()
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < QuestionName.Length; i++)
            {
                if (i == 0)
                    sb.Append("<div class='tab-pane fade in active " + QuestionName[i] + "Table " + QuestionName[i] + "Chart'></div>");
                else
                    sb.Append("<div class='tab-pane fade " + QuestionName[i] + "Table " + QuestionName[i] + "Chart'></div>");
            }
            return sb.ToString();
        }
  


       


        private void AddDynamicTableHtml(int tab_num, string[] question_name)
        {
            Table[] temp_table;
            temp_table = new Table[question_name.Length];

            Panel temp_div;
            StringBuilder sb=new StringBuilder();
            for (int i = 0; i < tab_num; i++)
            {

                temp_table[i] = new Table();

                
                temp_div = new Panel();
                tab_content_control.Controls.Add(temp_div);
                temp_div.ID = question_name[i] + "Table";
                temp_div.Controls.Add(temp_table[i]);
                MemberVariableSet(i);
                GenerateTable(table_cols, table_rows, temp_table[i]);
                
                if (i == 0)
                {
                    temp_div.Attributes.Add("class", "tab-pane fade in active "+question_name[i]+"Table");                   
                    
                    // nav_control innerHtml add string 
                    sb.Append("<li class='Question active " + question_name[i] + "'><a data-toggle='tab' href='." + question_name[i] + "Table" + "'>" + question_name[i] + "</a></li>");
                }
                else
                {
                    temp_div.Attributes.Add("class", "tab-pane fade "+ question_name[i] + "Table");
                    
                    // nav_control innerHtml add string 
                    sb.Append("<li class='Question " + question_name[i] + "'><a data-toggle='tab' href='." + question_name[i] + "Table" + "'>" + question_name[i] + "</a></li>");
                }
            }
            nav_control.InnerHtml = sb.ToString();

        }

 

        private void MemberQueAvgCal()
        {
            int Question_start=ScoreAnalysisList[0].QueIndex_start;
            int QuestionNum= ScoreAnalysisList[0].QuestionNum;
            int[] QuestionAvgTemp; 
            for (int QueIndex = 0; QueIndex < QuestionNum; QueIndex++)
            {
                int MemberQuestionNum = ScoreAnalysisList[0].MemberQuestionNum[QueIndex];
                QuestionAvgTemp = new int[MemberQuestionNum];
                for (int index = 0; index < MemberQuestionNum; index++)
                {
                    int sum = 0;
                    for (int student = 0; student < ScoreAnalysisList.Count; student++)
                        sum = Convert.ToInt16(ScoreAnalysisList[student].Grade[QueIndex][Question_start+index]) + sum;
                    sum = sum / ScoreAnalysisList.Count;
                    QuestionAvgTemp[index] = sum;
                }
                QuestionAvg.Add(QuestionAvgTemp);
            }

           
        }


        private void MemberVariableSet(int Question_num)
        {
            currentQuestion = Question_num;
            table_cols = ScoreAnalysisList[0].Grade[currentQuestion].Length+1;// +1 mean student column
            studentNum = ScoreAnalysisList.Count;
            table_rows = studentNum+AddRowsName.Count;
            
            MemberQuestionNum = ScoreAnalysisList[0].MemberQuestionNum[currentQuestion];
            
        }

        protected void DownLoadToExl_Click(object sender, EventArgs e)
        {
            Debug.WriteLine(currentQuestion);
            DownLoadFile();
            
        }

        private void DownLoadFile() // Convert Table to excel file
        {
            Response.ClearContent();
            Response.AddHeader("content-disposition", "attachment; filename= " + DateTime.Now.ToString("yyyyMMdd") + "成績清單.xls");
            Response.ContentType = "application/excel";
            Response.Write('\uFEFF');       // Add this, then the saved file will include BOM.
            StringWriter tw = new StringWriter();
            HtmlTextWriter hw = new HtmlTextWriter(tw);
            tab_content_control.RenderControl(hw);
            this.EnableViewState = false;
            Response.Write(tw.ToString());
            Response.End();

        }

        private void InsertTableStr(int row, int col, string str_insert)
        {
            TableCell tc_temp;
            tc_temp = (TableCell)FindControl("TextBoxRow_"+row+"Col_" + col+"_"+currentQuestion);
            tc_temp.Text = str_insert;
            
        }
        private void InsertTableStr(int row, int col, string str_insert,string Classname_Insert)
        {
            TableCell tc_temp;    
            tc_temp = (TableCell)FindControl("TextBoxRow_" + row + "Col_" + col + "_" + currentQuestion);
            tc_temp.Attributes.Add("class", Classname_Insert);
            tc_temp.Text = str_insert;
            
        }


        private string GetTableStr(int row, int col)
        {
            TableCell tc_temp;
            tc_temp = (TableCell)FindControl("TextBoxRow_" + row + "Col_" + col + "_" + currentQuestion);
            return tc_temp.Text;
        }

        private void AddRow(string RowName)
        {
            AddRowsName.Add(RowName);
            
        }

        private void AddCol(string ColName)
        {
            AddColsName.Add(ColName);
            
        }

        private void GenerateTable(int colsCount, int rowsCount,Table table_select)
        {

            //Creat the Table and Add it to the Page
            table_select.Attributes.Add("border", "1");
            table_select.Attributes.Add("cellpadding", "1");
            table_select.Attributes.Add("cellspacing", "1");
            table_select.Style.Add("width", "100%");
       
            // Now iterate through the table and add your controls 
            for (int i = 0; i <= rowsCount; i++)
            {
                TableRow row = new TableRow();
                for (int j = 0; j < colsCount; j++)
                {
                    TableCell cell = new TableCell();
                    cell.ID = "TextBoxRow_" + i + "Col_" + j + "_" + currentQuestion;
                    row.Controls.Add(cell);
                    row.Cells.Add(cell);
                }
                table_select.Rows.Add(row);
            }

            for (int i = 1; i <= studentNum; i++)
            {
                for (int j = 0; j <ScoreAnalysisList[i - 1].Grade[currentQuestion].Length; j++)
                    InsertTableStr(i, j+1, ScoreAnalysisList[i - 1].Grade[currentQuestion][j]);
           }
            
            // Row 0 set
            for (int i = 0; i < FirstColDefault.Length; i++)
                InsertTableStr(0, i, FirstColDefault[i]);
            
            for (int i = 1; i <=MemberQuestionNum; i++)
                InsertTableStr(0, i+FirstColDefault.Length-1, MemberQuestionAnswer[currentQuestion][i],"MQ"+QuestionName[currentQuestion]);

            // Column 0 set
            for (int i = 1; i <= studentNum; i++)
                InsertTableStr(i, 0, ScoreAnalysisList[i - 1].StuCouHWDe_ID);
            
            for (int i = studentNum + 1; i <= rowsCount; i++)
                InsertTableStr(i, 0, AddRowsName[i - rowsCount]);

                
            //Average Calculage
            for (int index = 0; index <MemberQuestionNum; index++)
            {
                string sum = QuestionAvg[currentQuestion][index].ToString();
                InsertTableStr(rowsCount, index + FirstColDefault.Length,sum,"Average"+QuestionName[currentQuestion]);
            }
            int avg_total=0;
            for (int i = 0; i < studentNum; i++)
                avg_total += Convert.ToInt16(ScoreAnalysisList[i].Grade[currentQuestion][0]);
            avg_total /= studentNum;
            InsertTableStr(rowsCount, 1, avg_total.ToString());
            
        }

    }
}<file_sep>using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// Summary description for ScoreAnalysisM
/// </summary>
public class ScoreAnalysisM
{
    public string StuCouHWDe_ID;
    public List<string[]> Grade=new List<string[]>();
    public int QuestionNum;
    public int[] MemberQuestionNum;
    public int QueIndex_start=1;
    public bool XMLerror = false;
  

    public ScoreAnalysisM(string id, string AnswerStr,string QuesOdrStr,List<string> xmlFile ,Hashtable[] correctAnswerHT)
    {


        //string[] temp_str_ar;
        StuCouHWDe_ID = id;
        string[] AnswerStr_Question= AnswerStr.Remove(AnswerStr.Length - 1).Split(':');
        string[] QuesOdrStr_Question = QuesOdrStr.Remove(QuesOdrStr.Length - 1).Split(':');
        MemberQuestionNum = new int[AnswerStr_Question.Length];
        QuestionNum = AnswerStr_Question.Length;
        for (int i = 0; i < AnswerStr_Question.Length; i++)
        {
            
            string[] AnswerStr_MemQuestion = AnswerStr_Question[i].Split(',');
            string[] QuesOdrStr_MemQuestion = QuesOdrStr_Question[i].Split(',');
            if (xmlFile[i] != AnswerStr_MemQuestion[0])
                XMLerror = true;
            MemberQuestionNum[i] = QuesOdrStr_MemQuestion.Length-QueIndex_start;
            Grade.Add(new string[QuesOdrStr_MemQuestion.Length]);
            int grade_perQuestion = 100 / QuesOdrStr_MemQuestion.Length;
            int correct_num = 0;
            for (int index = 1; index < QuesOdrStr_MemQuestion.Length; index++)
            {
                
                string compare_valstr=correctAnswerHT[i][QuesOdrStr_MemQuestion[index]].ToString();
                if (compare_valstr == AnswerStr_MemQuestion[index])
                {
                    Grade[i][index] = grade_perQuestion.ToString();
                    correct_num++;
                }
                else
                    Grade[i][index] = 0.ToString();
            }
            Grade[i][0] = (correct_num * grade_perQuestion).ToString();
        }
    }


}<file_sep>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// Summary description for ScoreAnalysisM
/// </summary>
public class ScoreAnalysisM
{
    public string StuCouHWDe_ID;
    public List<string[]> Grade=new List<string[]>();
    public int QuestionNum;
    public int[] MemberQuestionNum;
    public int QueIndex_start=3;

    public ScoreAnalysisM(string id,string grade_str)
    {
        

        string[] temp_str_arr = MemberQueSpilt(grade_str);
        StuCouHWDe_ID = id;
        for (int i = 0; i < QuestionNum; i++)
        {
            MemberQueGradeSpilt(temp_str_arr[i], i);
        }

    }

    private string[] MemberQueSpilt(string grade_str)
    {
        string[] temp_str_arr = grade_str.Remove(grade_str.Length-1).Split(':');
        QuestionNum = temp_str_arr.Length;
        MemberQuestionNum = new int[QuestionNum];
        return temp_str_arr;
    }

    private string[] MemberQueGradeSpilt(string grade_member_str,int questionNum)
    {
        string[] temp_str_arr = grade_member_str.Split(',');
        MemberQuestionNum[questionNum] = temp_str_arr.Length - QueIndex_start;
        Grade.Add(temp_str_arr);
        return temp_str_arr;
    }


}<file_sep>
GradeDiagramPlot Webform Document

目的 : 結合前後端的script來達成動態產生表格，以及運算平均值、繪圖。


Step 1 前端配置以便後端使用id動態修改內部Html

    <!--在前端aspx擋裡的head標籤裡套用d3與c3等javascript、css script讓
        後端傳入的javascript能使用 -->
    <head runat="server"> 
    <script src="./d3-3.5.0/d3.min.js" charset="utf-8"></script>
    <script src="./c3-0.4.15/c3.min.js"></script>
    <link href="./c3-0.4.15/c3.css" rel="stylesheet"/>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title></title>
    </head>




    <!--在body標籤裡form1這個form底下加上一個id為chart並讓他runat server能用
        後端C# script來進行內部html的控制-->
    <form id="form1" runat="server">
      <div> </div>
    </form>
    <div id="chart" runat="server">


Step 2 後端C# script GradeDiagramPlot.aspx.cs Doc

功用: 作為後端Script，最主要的作用是透過Page_Load這個複寫函式，當一進前端頁面就會執行這個function。而在這個class寫的private member 與private function都是Page_Load用來動態生成Table用的。

public member variable :

            // 此字串矩陣裡為Table的預設欄位，不受動態配置的欄位
            public string []FirstColDefault = {"總分"};
            // 此List<ScoreAnalysisM> 用來存把DB的資料以學生為單位存入這條List裡
            // 以便之後用來製作動態Table或跟外面做連接
            public List<ScoreAnalysisM> StuScoreStore=new List<ScoreAnalysisM>();



private member variable :

            // Table 總行數與總列數
            private int table_rows;
            private int table_cols;
            // QuestionAvg 這個Array是用來存每題運算後的平均值
            private int []QuestionAvg;
            // 總題數，目前以每個題數一樣為準
            private int QuestionNum;
            // 在首行與首列額外增加的行列名稱(Ex.Total行、Avg列 etc.)
            private List<string> AddRows = new List<string>();
            private List<string> AddCols = new List<string>();
            // 用來做TableCell暫存以便存取Table Date的資料
            private TableCell tc_temp;


// 使用priave因為這個script裡用的function都只限於這個script所以都封裝在此，並讓之後複寫的Page_Load function使用
private member function : 

            // 用來增加首行額外的欄位(Ex.Total)，Input為要輸入的欄位名稱
            private void AddRow(string RowName);
             // 用來增加首列額外的欄位(Ex.Avg)，Input為要輸入的欄位名稱
            private void AddCol(string ColName);
            // 用來動態產生Table的function，Input為Table的行術與列數
            private void GenerateTable(int colsCount, int rowsCount);
            // 新增以RowName命名的列
            private void AddRow(string RowName);
            // 新增以ColName命名的列
            private void AddCol(string ColName);
            // 取得Table row列col行的字串
            private string GetTableStr(int row, int col);
            // 修改 Table row列col行的字串
            private void InsertTableStr(int row, int col, string str_insert);
            


之後複寫class裡 void Page_Load(object sender, EventArgs e) 讓後端在Load Page時會受到這個function的控制。

// Code 裡分為四個部分Initalize the ScoreAnalysisM List、Initalize the Page member variable、

  Generate Table Function 、後端控制Chart Div。


    protected void Page_Load(object sender, EventArgs e)
            {
                //Get all the data from ScoreDetailTB table
                DataTable dt = CsDBOp.GetAllTBData();
    
                //Get the retrieved data from each row of the retrieved data table
                foreach (DataRow dr in dt.Rows)
                {
                    ScoreAnalysisM log = new ScoreAnalysisM();
    
                    log.StuCouHWDe_ID = dr.Field<string>("StuCouHWDe_ID");
                    log.Grade = dr.Field<string>("Grade");
                    log.QuestionNum = log.Grade.Split(',')[1];
                    ScoreAnalysisList.Add(log);
                }
                
                //Initalize the Page
                QuestionNum = ScoreAnalysisList[0].Grade.Split(',').Length-FirstColDefault.Length;
                table_cols = FirstColDefault.Length+QuestionNum;
                table_rows = ScoreAnalysisList.Count;
                studentNum = table_rows;
    
                // Add a row named Avg
                AddRow("Avg");
                
                // Generate Table Function 
                GenerateTable(table_cols, table_rows);
                
                // 後端控制Chart Div裡的Html String 加入JavaScript的Script String
                string tempcolstr ="";
                for (int i = 0; i < QuestionNum;i++ )
                {
                    string temp2;
                    temp2 = "['第" + (i+1) + "題'," + QuestionAvg[i] + "],";
                    tempcolstr = tempcolstr + temp2;
                    
                }
                // 此段Script採用C3.js，其Reference；http://c3js.org/reference.html
                chart.InnerHtml="<script>var chart = c3.generate({bindto: '#chart',data: {columns: ["+tempcolstr+"],type : 'pie'}});</script>";
            }

P.S 想之後把Page_Load和GenerateTable裡的function拆得更細會不會可以做的更多可變性，但想說這個Script裡function或是variable都只可能在這個C#裡使用，之後想改的話只要改Script裡的東西，想問問看學長的意見。

P.S 以後可能會出問題的點可能是題數的問題，目前我以一個private string來存一個大家都一樣的題數，但我在ScoreAnalysis這個Class裡加了一個public string QuestionNum用來存各自的題數，以便之後要對動態表格格式做修改。
 
P.S 之後會再寫每個人題數不一樣的Table，這種table因為不是方正的Table，所以Table產生得流程會不一樣，以及平均值的算法是以哪題為準。這修都會照程Document與Flow得改寫。
