🌵 建立 Dealer Manager - Content Page 後台頁面 - 代理商功能。
📌 後台代理商功能需要的功能如下 :
🌵 灰色欄位設定為 ReadOnly,無法修改。
🌵 這個區域資料較多,Visible 先設成 false 不顯示,選完國家及代理商後才顯示。
👺 代理商的 Thumbnail 縮圖建議用 asp:Literal 控制項送 HTML 的作法製作,如果使用 asp:Image 控制項,在圖檔名稱有中文時,後端使用 .ImageUrl 設定控制項路徑,會在渲染後因為中文轉碼而讀不到圖片。
🧠 可以在資料庫圖表的關聯性中設定屬性,將關聯性 " INSERT 及 UPDATE 規格" 裡面的刪除規則,設定為串聯刪除 (**重疊顯示 - Cascade **),這樣如果刪除國家時,會一併刪除該國的區域代理商,可以避免手殘亂刪時出現錯誤,當然也會寫在後台的規則裡。
👀 串聯刪除-設定參考 : 如何在 SQL Server 資料庫設計「一對一」表格關聯
🌵 先在原始檔頁選擇點選控制項該行程式碼,再轉到設計頁可以避免選錯,點擊側開選項設定資料來源時,要勾 countrySort 跟 id 這樣設定完成後,再點擊側開選項選擇資料來源時,資料欄位值才能選到 id。
👺 這裡很重要,有設定的話 SQL 語法會變很簡單,後面有遇到下拉選單最好都設定。
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack) {
        DropDownList1.DataBind(); //先綁定取得選取預設值
        showDealerList();
    }
}
private void showDealerList()
{
    //依下拉選單選取國家的值 (id) 取得地區分類
    string selCountry_id = DropDownList1.SelectedValue;
    SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
    string sql = "SELECT area FROM Dealers WHERE country_ID = @selCountry_id";
    SqlCommand command = new SqlCommand(sql, connection);
    command.Parameters.AddWithValue("@selCountry_id", selCountry_id);
    //取得地區分類
    connection.Open();
    SqlDataReader readerCountry = command.ExecuteReader();
    while (readerCountry.Read()) {
        string typeStr = readerCountry["area"].ToString();
        // RadioButtonList 增加方式
        ListItem listItem = new ListItem();
        listItem.Text = typeStr;
        listItem.Value = typeStr;
        RadioButtonList1.Items.Add(listItem);
    }
    connection.Close();
}
protected void BtnAddArea_Click(object sender, EventArgs e)
{
    //取得下拉選單國家的值 (id)
    string selCountry_id = DropDownList1.SelectedValue;
    //取得輸入欄內的文字
    string areaStr = TBoxAddArea.Text;
    //判斷是否重複用
    bool isRepeat = false;
    //取得地區分類
    SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
    string sql = $"SELECT area FROM Dealers WHERE country_ID = @selCountry_id";
    SqlCommand command = new SqlCommand(sql, connection);
        command.Parameters.AddWithValue("@selCountry_id", selCountry_id);
    connection.Open();
    SqlDataReader readerCountry = command.ExecuteReader();
    while (readerCountry.Read()) {
        string typeStr = readerCountry["area"].ToString();
        //判斷有無重複名稱
        if (areaStr.Equals(typeStr)) {
            isRepeat = true;
            //重複警告
            TBoxAddArea.ForeColor = Color.Red;
            TBoxAddArea.Text = "The area name is repeated!";
        }
    }
    connection.Close();
    //輸入的區域名稱不重複才執行
    if (!isRepeat) {
        TBoxAddArea.ForeColor = Color.Black;
        //新增區域
        string sql2 = "INSERT INTO Dealers (country_ID, area) VALUES(@selCountry_id, @areaStr)";
        SqlCommand command2 = new SqlCommand(sql2, connection);
        command2.Parameters.AddWithValue("@selCountry_id", selCountry_id);
        command2.Parameters.AddWithValue("@areaStr", areaStr);
        connection.Open();
        command2.ExecuteNonQuery();
        connection.Close();
        //畫面渲染
        RadioButtonList1.Items.Clear(); //清掉舊的
        BtnDelArea.Visible = false;
        DealerList.Visible = false;
        LabUploadImg.Visible = false;
        UpdateDealerListLab.Visible = false;
        showDealerList(); //讀取新的
        //清空輸入欄位
        TBoxAddArea.Text = "";
    }
}
protected void BtnDelArea_Click(object sender, EventArgs e)
{
    //取得選取資料的值
    string selAreaStr = RadioButtonList1.SelectedValue;
    //刪除實際圖檔檔案
    SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
    string sql = "SELECT dealerImgPath FROM Dealers WHERE area = @selAreaStr";
    SqlCommand command = new SqlCommand(sql, connection);
    command.Parameters.AddWithValue("@selAreaStr", selAreaStr);
    connection.Open();
    SqlDataReader reader = command.ExecuteReader();
    if (reader.Read()) {
        string imgPath = reader["dealerImgPath"].ToString();
        if (!imgPath.Equals("")) {
            string savePath = Server.MapPath($"~/Tayanahtml/upload/Images/{imgPath}");
            File.Delete(savePath);
        }
    }
    connection.Close();
    //刪除資料庫該筆資料
    string sqlDel = "DELETE FROM Dealers WHERE area = @selAreaStr";
    SqlCommand commandDel = new SqlCommand(sqlDel, connection);
    commandDel.Parameters.AddWithValue("@selAreaStr", selAreaStr);
    connection.Open();
    commandDel.ExecuteNonQuery();
    connection.Close();
    //畫面渲染
    RadioButtonList1.Items.Clear(); //清掉舊的
    BtnDelArea.Visible = false;
    DealerList.Visible = false;
    LabUploadImg.Visible = false;
    UpdateDealerListLab.Visible = false;
    showDealerList(); //讀取新的
    TBoxAddArea.ForeColor = Color.Black;
    TBoxAddArea.Text = "";
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
    //當選擇國家改變時刷新畫面資料
    RadioButtonList1.Items.Clear();
    BtnDelArea.Visible = false;
    DealerList.Visible = false;
    LabUploadImg.Visible = false;
    UpdateDealerListLab.Visible = false;
    showDealerList();
}
AutoPostBack="True",這樣選取改變時才會刷新頁面。private void showDealerListTable()
{
    //當區域選取時才顯示代理商資料表
    DealerList.Visible = true;
    //放入國家顯示文字
    TBoxCountry.Text = DropDownList1.SelectedItem.Text;
    //放入區域
    TBoxArea.Text = RadioButtonList1.SelectedValue;
    //依選取區域的值連接資料庫取得資料
    string selAreaStr = RadioButtonList1.SelectedValue;
    SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
    string sql = $"SELECT * FROM Dealers WHERE area = @selAreaStr";
    SqlCommand command = new SqlCommand(sql, connection);
    command.Parameters.AddWithValue("@selAreaStr", selAreaStr);
    connection.Open();
    SqlDataReader reader = command.ExecuteReader();
    //放入個別資料
    while (reader.Read()) {
        string savePath = reader["dealerImgPath"].ToString();
        LiteralImg.Text = $"<img alt='Thumbnail Image' src='/Tayanahtml/upload/Images/{savePath}' Width='209px'/>";
        TBoxImage.Text = reader["dealerImgPath"].ToString();
        TBoxName.Text = reader["name"].ToString();
        TBoxContact.Text = reader["contact"].ToString();
        TBoxAddress.Text = reader["address"].ToString();
        TBoxTel.Text = reader["tel"].ToString();
        TBoxFax.Text = reader["fax"].ToString();
        TBoxEmail.Text = reader["email"].ToString();
        TBoxLink.Text = reader["link"].ToString();
        TBoxDate.Text = reader["initDate"].ToString();
    }
    connection.Close();
}
🌵 用 .SelectedItem.Text 來取得下拉選單選取的顯示文字 !
🌵 圖片路徑 savePath 是用來送到前台的 HTML 內容,所以前面不是波浪符號喔 !
protected void RadioButtonList1_SelectedIndexChanged(object sender, EventArgs e)
{
    //區域預設不選取,但當選取切換時顯示刪除按鈕
    BtnDelArea.Visible = true;
    LabUploadImg.Visible = false;
    UpdateDealerListLab.Visible = false;
    //顯示區域代理商資料表
    showDealerListTable();
    TBoxAddArea.ForeColor = Color.Black;
    TBoxAddArea.Text = "";
}
AutoPostBack="True",這樣選取改變時才會刷新頁面。protected void BtnUploadImg_Click(object sender, EventArgs e)
{
    //設定存檔路徑,需填完整路徑,結尾反斜線如果沒加要用 Path.Combine() 可自動添加
    string savePath = Server.MapPath("~/Tayanahtml/upload/Images/");
    //判斷有選檔案才可上傳
    if (FileUpload1.HasFile) {
        //取得選擇區域名稱
        string selAreaStr = RadioButtonList1.SelectedValue;
        //先執行刪除舊圖檔
        SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
        string sqlDel = "SELECT dealerImgPath FROM Dealers WHERE area = @selAreaStr";
        SqlCommand commandDel = new SqlCommand(sqlDel, connection);
        commandDel.Parameters.AddWithValue("@selAreaStr", selAreaStr);
        connection.Open();
        SqlDataReader reader = commandDel.ExecuteReader();
        if (reader.Read()) {
            string delFileName = reader["dealerImgPath"].ToString();
            //有舊圖才執行刪除
            if (!String.IsNullOrEmpty(delFileName)) {
                File.Delete(savePath + delFileName);
            }
        }
        connection.Close();
        //儲存圖片檔案及圖片名稱
        //檢查專案資料夾內有無同名檔案,有同名就加流水號
        DirectoryInfo directoryInfo = new DirectoryInfo(savePath);
        //取得選取檔案名稱
        string fileName = FileUpload1.FileName;
        string[] fileNameArr = fileName.Split('.');
        int count = 0;
        foreach (var fileItem in directoryInfo.GetFiles()) {
            if (fileItem.Name.Contains(fileNameArr[0])) {
                count++;
            }
        }
        fileName = fileNameArr[0] + $"({count + 1})." + fileNameArr[1];
        FileUpload1.SaveAs(savePath + fileName);
        //渲染畫面
        DateTime nowtime = DateTime.Now;
        LabUploadImg.Visible = true;
        LabUploadImg.ForeColor = Color.Green;
        LabUploadImg.Text = "*Upload Success! - " + nowtime.ToString("G");
        //更新資料庫資料
        string sql = "UPDATE Dealers SET dealerImgPath = @fileName WHERE area = @selAreaStr";
        SqlCommand command = new SqlCommand(sql, connection);
        command.Parameters.AddWithValue("@fileName", fileName);
        command.Parameters.AddWithValue("@selAreaStr", selAreaStr);
        connection.Open();
        command.ExecuteNonQuery();
        connection.Close();
        //渲染畫面
        showDealerListTable();
    }
    else {
        //警告沒有選取檔案
        LabUploadImg.Visible = true;
        LabUploadImg.ForeColor = Color.Red;
        LabUploadImg.Text = "*Need Choose File!";
    }
}
👀 DirectoryInfo 類別參考官網 : DirectoryInfo 類別
👀 GetFiles() 方法參考官網 : DirectoryInfo.GetFiles 方法
🌵 用 .Contains 才能把已經加過流水號的檔案算進計算的數量裡。
🌵 FileUpload 控制項需配合一個按鈕控制項來執行上傳功能。
👺 儲存圖檔前記得先檢查有無同名檔案,而且檢查圖檔要針對存放的資料夾,因為可能會出現同名但內容不同的圖片,避免其它頁面有使用同名檔案被取代。
protected void BtnUpdateDealerList_Click(object sender, EventArgs e)
{
    //依國家及選取區域的值連接資料庫取得資料
    string selAreaStr = RadioButtonList1.SelectedValue;
    string selCountry_id = DropDownList1.SelectedValue;
    SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
    string sql = $"UPDATE Dealers SET name=@name, contact=@contact, address=@address, tel=@tel, fax=@fax, email=@email, link=@link WHERE country_ID=@selCountry_id AND area = @selAreaStr";
    SqlCommand command = new SqlCommand(sql, connection);
    command.Parameters.AddWithValue("@name", TBoxName.Text);
    command.Parameters.AddWithValue("@contact", TBoxContact.Text);
    command.Parameters.AddWithValue("@address", TBoxAddress.Text);
    command.Parameters.AddWithValue("@tel", TBoxTel.Text);
    command.Parameters.AddWithValue("@fax", TBoxFax.Text);
    command.Parameters.AddWithValue("@email", TBoxEmail.Text);
    command.Parameters.AddWithValue("@link", TBoxLink.Text);
    command.Parameters.AddWithValue("@selCountry_id", selCountry_id);
    command.Parameters.AddWithValue("@selAreaStr", selAreaStr);
    connection.Open();
    command.ExecuteNonQuery();
    connection.Close();
    //渲染上傳成功提示
    DateTime nowtime = DateTime.Now;
    UpdateDealerListLab.Visible = true;
    UpdateDealerListLab.Text = "*Upload Success! - " + nowtime.ToString("G");
    Page.SetFocus(UpdateDealerListLab);
}
13. 渲染畫面後,進行功能測試,確認無誤,完成此頁後台功能~
📢 這個頁面因為放入兩組會互相影響的功能,所以關鍵會在互動時的項目開關,如上篇提到的增刪國家時,國家下拉選單要同步更新,而在下拉選取不同國家時預設不選取任何區域,是避免反覆讀取還不確定使用者要看的資料是哪個,而在選取區域後會秀出刪除區域的按鈕,刪除區域後又會回到預設不選取任何區域,另外選取區域後才會秀出這個國家這個區域的代理商細項資料,這些切換的細節,在第一次設計畫面交互時可能不太好想到,可以試著先畫草稿模擬想像。