Day 9 - 依 DEALERS 前台页面分析拆解後,逐步建立後台功能 (下) - 图档同名处理 - ASP.NET Web Forms C#

🌵 建立 Dealer Manager - Content Page 後台页面 - 代理商功能。


Dealer Manager 後台页面 - 代理商功能介绍 :

📌 後台代理商功能需要的功能如下 :

1. 单个国家会有多个区域代理商,因此需要对应单个国家能新增跟删除不同"区域"。

https://ithelp.ithome.com.tw/upload/images/20210923/20139487KtlUp9n7mH.jpg


2. 区域代理商的资料都是固定格式。

https://ithelp.ithome.com.tw/upload/images/20210923/20139487TBx2X1IzRw.jpg

  • 🌵 灰色栏位设定为 ReadOnly,无法修改。

  • 🌵 这个区域资料较多,Visible 先设成 false 不显示,选完国家及代理商後才显示。

  • 👺 代理商的 Thumbnail 缩图建议用 asp:Literal 控制项送 HTML 的作法制作,如果使用 asp:Image 控制项,在图档名称有中文时,後端使用 .ImageUrl 设定控制项路径,会在渲染後因为中文转码而读不到图片。



Dealer Manager 後台页面实作 :

1. 建立区域代理商资料表

https://ithelp.ithome.com.tw/upload/images/20210923/20139487g6mIdZ1dRp.jpg


2. 将国家资料表的 id 与区域代理商资料表 country_ID 建立关联

https://ithelp.ithome.com.tw/upload/images/20210923/20139487lFOKNC8iVI.jpg

  • 🧠 可以在资料库图表的关联性中设定属性,将关联性 " INSERT 及 UPDATE 规格" 里面的删除规则,设定为串联删除 (**重叠显示 - Cascade **),这样如果删除国家时,会一并删除该国的区域代理商,可以避免手残乱删时出现错误,当然也会写在後台的规则里。

  • 👀 串联删除-设定参考 : 如何在 SQL Server 资料库设计「一对一」表格关联

3. 在国家下拉列表 DropDownList 控制项直接使用辅助精灵连接资料库并设定值为对应 id

https://ithelp.ithome.com.tw/upload/images/20210923/20139487TVDMg5CyEL.jpg

  • 🌵 先在原始档页选择点选控制项该行程序码,再转到设计页可以避免选错,点击侧开选项设定资料来源时,要勾 countrySort 跟 id 这样设定完成後,再点击侧开选项选择资料来源时,资料栏位值才能选到 id。

  • 👺 这里很重要,有设定的话 SQL 语法会变很简单,後面有遇到下拉选单最好都设定。

4. 在 Page_Load 事件中加入 showDealerList(); 方法读取 RadioButtonList 控制项资料如下

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack) {
        DropDownList1.DataBind(); //先绑定取得选取预设值
        showDealerList();
    }
}


5. 建立 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();
}


6. 在增加区域的 Add 按钮 OnClick 事件加入以下後置程序码

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 = "";
    }
}


7. 在删除区域的 Delete Area 按钮 OnClick 事件加入以下後置程序码

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 = "";
}


8. 在国家下拉列表的 DropDownList 控制项 OnSelectedIndexChanged 事件加入以下後置程序码控制画面渲染

protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
    //当选择国家改变时刷新画面资料
    RadioButtonList1.Items.Clear();
    BtnDelArea.Visible = false;
    DealerList.Visible = false;
    LabUploadImg.Visible = false;
    UpdateDealerListLab.Visible = false;
    showDealerList();
}
  • 👺 记得在 .aspx 页面加上AutoPostBack="True",这样选取改变时才会刷新页面。

9. 建立显示区域代理商资料表 showDealerListTable(); 读取资料方法

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 内容,所以前面不是波浪符号喔 !

10. 在区域列表的 RadioButtonList 控制项 OnSelectedIndexChanged 事件加入以下後置程序码控制画面渲染

protected void RadioButtonList1_SelectedIndexChanged(object sender, EventArgs e)
{
    //区域预设不选取,但当选取切换时显示删除按钮
    BtnDelArea.Visible = true;
    LabUploadImg.Visible = false;
    UpdateDealerListLab.Visible = false;
    //显示区域代理商资料表
    showDealerListTable();
    TBoxAddArea.ForeColor = Color.Black;
    TBoxAddArea.Text = "";
}
  • 👺 记得在 .aspx 页面加上AutoPostBack="True",这样选取改变时才会刷新页面。

11. 在 FileUpload 控制项後加上一个 Upload 按钮,并在 Upload 按钮的 OnClick 事件加入以下後置程序码,并进行图档同名处理後,完成上传功能

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 控制项需配合一个按钮控制项来执行上传功能。

  • 👺 储存图档前记得先检查有无同名档案,而且检查图档要针对存放的资料夹,因为可能会出现同名但内容不同的图片,避免其它页面有使用同名档案被取代。

12. 在上传代理商资料的 Update Dealer List Value 按钮 OnClick 事件加入以下後置程序码

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. 渲染画面後,进行功能测试,确认无误,完成此页後台功能~



本日总结 :

📢 这个页面因为放入两组会互相影响的功能,所以关键会在互动时的项目开关,如上篇提到的增删国家时,国家下拉选单要同步更新,而在下拉选取不同国家时预设不选取任何区域,是避免反覆读取还不确定使用者要看的资料是哪个,而在选取区域後会秀出删除区域的按钮,删除区域後又会回到预设不选取任何区域,另外选取区域後才会秀出这个国家这个区域的代理商细项资料,这些切换的细节,在第一次设计画面交互时可能不太好想到,可以试着先画草稿模拟想像。

  • 明日将介绍制作 DEALERS 前台页面的後端细节。

<<:  Day-23 你没想到的Excel average知识

>>:  [火锅吃到饱-7] 大喜锅 - 南屯店 - 平日午餐250元吃到饱 | 学生&小资族首选

DAY30 结语

哇~~~终於完成三十天的文章了,这里面记录了满满我对於这个专案学习的过程,以及在最後展现出成果实在是...

[铁人赛 Day09] React Context(上)-单纯的用法

Why Context 在写 React 网站的时候,因为资料都是由上而下的藉由元件传递,有些情况,...

30天打造品牌特色电商网站 Day.9 RWD响应式设计介绍

哈罗~很快的已经来到了第九天,前面带给大家都是一些网页的基础,後面会针对各种主题有更深入的探讨喔,今...

[Day20] NLP会用到的模型(四)-LSTM实现POS

一. 资料准备 此资料与[Day9]的资料一样为conllu档,都是作为POS任务 架构如下,每个词...

[访谈] APCS x 自学生 Jason

今天邀请到和我相同年纪,但目前已经在业界工作的 Jason 分享,在整个访谈过程刷新了身为小小学生的...