=x= 🌵 建立 Yacht Manager - Content Page 後台頁面。
📌 在 Home 頁面的輪播大圖照片,可以知道每個遊艇型號都會有一張圖,圖片右下角會對應更換遊艇型號,而左上角會對應遊艇型號是新建造就出現紅色標籤,遊艇型號可從 Yachts 頁面側邊欄看到全部遊艇型號及特殊註記,點擊側邊欄會發現如新聞列表頁的模式,會在網址列出現網址傳值是使用 GUID 隨機碼來對應資料;另外,在首頁的輪播大圖下方有 3 組新聞圖卡,查看原始碼可以發現有個 Top 標籤,是用來加註焦點新聞的圖標,效果可以參考上圖右下區塊。
🌵 遊艇型號是新設計並沒有配合對應的圖標,可以自行拿新建造的圖片修圖後使用。
🌵 新聞圖卡的 Top 標籤,可以將 HTML 裡的
style="display: none"
拿掉就能看到效果。
🧠 上半部 - 多圖上傳相簿功能並添加下拉式選單配合切換。
🧠 下半部 - 左側含勾選項目及2個輸入框的遊艇型號添加區,右側為遊艇型號列表。
<div class="input-group my-3">
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True" DataSourceID="SqlDataSource1" DataTextField="yachtModel" DataValueField="id" Width="50%" Font-Bold="True" class="btn btn-outline-primary dropdown-toggle" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged"></asp:DropDownList>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:TayanaYachtConnectionString %>" SelectCommand="SELECT [yachtModel], [id] FROM [Yachts]"></asp:SqlDataSource>
<asp:FileUpload ID="imageUpload" runat="server" class="btn btn-outline-primary btn-block" AllowMultiple="True" />
<asp:Button ID="UploadBtn" runat="server" Text="Upload" class="btn btn-primary" OnClick="UploadBtn_Click" />
</div>
<hr />
<h6>Banner Image List :</h6>
<h6><span class="badge badge-pill badge-success text-dark">* The first image will be the home page banner !</span></h6>
<h6>Step1. To upload one image to be the home page banner.</h6>
<h6>Step2. Then upload other images.</h6>
<asp:RadioButtonList ID="RadioButtonList" runat="server" class="my-3 mx-auto" AutoPostBack="True" CellPadding="10" RepeatColumns="5" RepeatDirection="Horizontal" OnSelectedIndexChanged="RadioButtonListH_SelectedIndexChanged" ></asp:RadioButtonList>
<asp:Button ID="DelImageBtn" runat="server" Text="Delete Image" type="button" class="btn btn-danger btn-sm" OnClientClick="return confirm('Are you sure you want to delete?')" Visible="False" OnClick="DelHImageBtn_Click" />
<asp:CheckBox ID="CBoxNewDesign" runat="server" Text="NewDesign" Width="50%" />
<asp:CheckBox ID="CBoxNewBuilding" runat="server" Text="NewBuilding" Width="50%" />
<div class="input-group mb-3">
<asp:TextBox ID="TBoxAddYachtModel" runat="server" type="text" class="form-control" placeholder="Model" Width="30%" ></asp:TextBox>
<asp:TextBox ID="TBoxAddYachtLength" runat="server" type="text" class="form-control" placeholder="Length" ></asp:TextBox>
<div class="input-group-append">
<asp:Button ID="BtnAddYacht" runat="server" Text="Add" class="btn btn-outline-primary btn-block" OnClick="BtnAddYacht_Click" />
</div>
</div>
🌵 遊艇型號的數字其實是長度英呎的含意,是行業的慣性用語。
🌵 分開輸入是因為其它頁面會取出後面的數值,及控制遊艇型號出現時的排版效果。
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="id" DataSourceID="SqlDataSource2" BackColor="White" BorderColor="#CCCCCC" BorderStyle="None" BorderWidth="1px" CellPadding="3" Width="100%" OnRowDeleted="DeletedModel" OnRowUpdated="UpdatedModel" OnRowDeleting="DeletingModel">
<Columns>
<asp:CommandField ButtonType="Button" CancelText="Cancel" DeleteText="Delete" EditText="Edit" HeaderText="Edit" InsertText="Insert" NewText="New" SelectText="Select" ShowEditButton="True" ControlStyle-CssClass='btn btn-primary btn-block' ControlStyle-BorderColor="#66CCFF" ControlStyle-BorderStyle="Solid" ControlStyle-BorderWidth="1px" ControlStyle-ForeColor="White" >
<ControlStyle BorderColor="#66CCFF" BorderWidth="1px" BorderStyle="Solid" CssClass="btn btn-primary btn-block" ForeColor="White"></ControlStyle>
</asp:CommandField>
<asp:BoundField DataField="id" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="id" />
<asp:BoundField DataField="yachtModel" HeaderText="Yacht Model" SortExpression="yachtModel" />
<asp:CheckBoxField DataField="isNewDesign" HeaderText="New Design" SortExpression="isNewDesign" />
<asp:CheckBoxField DataField="isNewBuilding" HeaderText="New Building" SortExpression="isNewBuilding" />
<asp:BoundField DataField="initData" HeaderText="Creation Date" SortExpression="initData" InsertVisible="False" ReadOnly="True" />
<asp:TemplateField HeaderText="Delete" ShowHeader="False">
<ItemTemplate>
<asp:LinkButton ID="BtnDeleteCountry" runat="server" CommandName="Delete" Text="Delete" OnClientClick="return confirm('Are you sure you want to delete?')" CausesValidation="False"></asp:LinkButton>
</ItemTemplate>
<ControlStyle BorderColor="#66CCFF" BorderStyle="Solid" BorderWidth="1px" CssClass="btn btn-danger btn-block" ForeColor="White" />
</asp:TemplateField>
</Columns>
<FooterStyle BackColor="White" ForeColor="#000066" />
<HeaderStyle BackColor="#006699" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="White" ForeColor="#000066" HorizontalAlign="Left" />
<RowStyle ForeColor="#000066" />
<SelectedRowStyle BackColor="#669999" Font-Bold="True" ForeColor="White" />
<SortedAscendingCellStyle BackColor="#F1F1F1" />
<SortedAscendingHeaderStyle BackColor="#007DBB" />
<SortedDescendingCellStyle BackColor="#CAC9C9" />
<SortedDescendingHeaderStyle BackColor="#00547E" />
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:TayanaYachtConnectionString %>" SelectCommand="SELECT [id], [yachtModel], [isNewDesign], [isNewBuilding], [initData] FROM [Yachts]" DeleteCommand="DELETE FROM [Specification] WHERE [yachtModel_ID] = @id; DELETE FROM [Yachts] WHERE [id] = @id" UpdateCommand="UPDATE [Yachts] SET [yachtModel] = @yachtModel, [isNewDesign] = @isNewDesign, [isNewBuilding] = @isNewBuilding WHERE [id] = @id">
<DeleteParameters>
<asp:Parameter Name="id" Type="Int32" />
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="isNewBuilding" Type="Boolean" />
<asp:Parameter Name="isNewDesign" Type="Boolean" />
<asp:Parameter Name="yachtModel" Type="String" />
<asp:Parameter Name="id" Type="Int32" />
</UpdateParameters>
</asp:SqlDataSource>
🌵 OnRowDeleting 事件用來在刪除的同時,先取得型號並用來刪除相關圖檔及資料。
🌵 Command 加入同步刪除關聯資料的語法,可在製作後續頁面時回頭修改。
🌵 Parameter 需注意 CheckBoxField 的 Type 是 Boolean 類型。
👀 GridView 事件參考官網資料 : GridView 類別
protected void BtnAddYacht_Click(object sender, EventArgs e)
{
//插入空格區隔文字跟數字 (頁面細項標題會用到)
string yachtModelStr = TBoxAddYachtModel.Text + " " + TBoxAddYachtLength.Text;
//產生 GUID 隨機碼 + 時間2位秒數 (加強避免重複)
DateTime nowTime = DateTime.Now;
string nowSec = nowTime.ToString("ff");
string guidStr = Guid.NewGuid().ToString().Trim() + nowSec;
//取得勾選項目
string isNewDesign = CBoxNewDesign.Checked.ToString();
string isNewBuilding = CBoxNewBuilding.Checked.ToString();
//插入遊艇型號基本資料
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
string sql = "INSERT INTO Yachts (yachtModel, isNewDesign, isNewBuilding, guid) VALUES (@yachtModelStr, @isNewDesign, @isNewBuilding, @guidStr)";
SqlCommand command = new SqlCommand(sql, connection);
command.Parameters.AddWithValue("@yachtModelStr", yachtModelStr);
command.Parameters.AddWithValue("@isNewDesign", isNewDesign);
command.Parameters.AddWithValue("@isNewBuilding", isNewBuilding);
command.Parameters.AddWithValue("@guidStr", guidStr);
connection.Open();
command.ExecuteNonQuery();
connection.Close();
//畫面渲染
DropDownList1.DataBind();
GridView1.DataBind();
TBoxAddYachtModel.Text = "";
TBoxAddYachtLength.Text = "";
CBoxNewDesign.Checked = false;
CBoxNewBuilding.Checked = false;
DropDownList1.SelectedValue = yachtModelStr; //設定下拉選單選取項為新增項
RadioButtonList.Items.Clear(); //新添加型號還沒有任何圖片,記得要清空畫面
}
protected void DeletingModel(object sender, GridViewDeleteEventArgs e)
{
//在刪除狀態下先取得刪除項的索引鍵欄位值
string idStr = "";
foreach (DictionaryEntry entry in e.Keys) {
idStr = entry.Value.ToString();
}
//取出刪除的遊艇型號的組圖資料
string savePath = Server.MapPath("~/Tayanahtml/upload/Images/");
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
string sqlBannerImg = "SELECT bannerImgPathJSON FROM Yachts WHERE id = @idStr";
SqlCommand command = new SqlCommand(sqlBannerImg, connection);
command.Parameters.AddWithValue("@idStr", idStr);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.Read()) {
string loadJson = HttpUtility.HtmlDecode(reader["bannerImgPathJSON"].ToString());
//反序列化JSON格式
savePathList = JsonConvert.DeserializeObject<List<ImagePath>>(loadJson);
}
connection.Close();
//刪除組圖實際圖檔
for (int i = 0; i < savePathList.Count; i++) {
File.Delete(savePath + savePathList[i].SavePath);
}
//以下為製作後續頁面後需執行的程式碼
//取出刪除的遊艇型號的 Layout 組圖資料
string sqlLayoutImg = "SELECT layoutDeckPlanImgPathJSON FROM Yachts WHERE id = @idStr";
SqlCommand command2 = new SqlCommand(sqlLayoutImg, connection);
command2.Parameters.AddWithValue("@idStr", idStr);
connection.Open();
SqlDataReader reader2 = command2.ExecuteReader();
if (reader2.Read()) {
string loadJson = HttpUtility.HtmlDecode(reader2["layoutDeckPlanImgPathJSON"].ToString());
//反序列化JSON格式
savePathList = JsonConvert.DeserializeObject<List<ImagePath>>(loadJson);
}
connection.Close();
//刪除組圖實際圖檔
for (int i = 0; i < savePathList.Count; i++) {
File.Delete(savePath + savePathList[i].SavePath);
}
//取出刪除的遊艇型號的 overview 規格圖片資料
string sqlDimImg = "SELECT overviewDimensionsImgPath FROM Yachts WHERE id = @idStr";
SqlCommand command3 = new SqlCommand(sqlDimImg, connection);
command3.Parameters.AddWithValue("@idStr", idStr);
connection.Open();
SqlDataReader reader3 = command3.ExecuteReader();
if (reader3.Read()) {
string imgPath = reader3["overviewDimensionsImgPath"].ToString();
//刪除實際圖檔
if (!String.IsNullOrWhiteSpace(imgPath)) {
File.Delete(savePath + imgPath);
}
}
connection.Close();
//取出刪除的遊艇型號的 overview 的 PDF 檔案資料
string sqlPDF = "SELECT overviewDownloadsFilePath FROM Yachts WHERE id = @idStr";
SqlCommand command4 = new SqlCommand(sqlPDF, connection);
command4.Parameters.AddWithValue("@idStr", idStr);
connection.Open();
SqlDataReader reader4 = command4.ExecuteReader();
if (reader4.Read()) {
string imgPath = reader4["overviewDownloadsFilePath"].ToString();
//刪除實際圖檔
if (!String.IsNullOrWhiteSpace(imgPath)) {
File.Delete(savePath + imgPath);
}
}
connection.Close();
}
//宣告 List 方便用 Add 依序添加圖檔資料
private List<ImagePath> savePathList = new List<ImagePath>();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack) {
DropDownList1.DataBind(); //先綁定,圖片才能取到型號
loadImageList();
}
}
private void loadImageList()
{
//取得下拉選單選取值
string selModel_id = DropDownList1.SelectedValue;
//連線資料庫取得首頁輪播圖資料
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
string sqlLoad = "SELECT bannerImgPathJSON FROM Yachts WHERE id = @selModel_id";
SqlCommand command = new SqlCommand(sqlLoad, connection);
command.Parameters.AddWithValue("@selModel_id", selModel_id);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.Read()) {
string loadJson = HttpUtility.HtmlDecode(reader["bannerImgPathJSON"].ToString());
//反序列化JSON格式
savePathList = JsonConvert.DeserializeObject<List<ImagePath>>(loadJson);
}
connection.Close();
if (savePathList?.Count > 0) {
//預設第一張上傳的圖片為該遊艇型號首頁圖片
bool firstCheck = true;
foreach (var item in savePathList) {
if (firstCheck) {
//替首張圖片加上醒目色彩邊框
ListItem listItem = new ListItem($"<img src='/Tayanahtml/upload/Images/{item.SavePath}' alt='thumbnail' class='img-thumbnail bg-success' width='200px'/>", item.SavePath);
RadioButtonList.Items.Add(listItem);
firstCheck = false;
}
else {
ListItem listItem = new ListItem($"<img src='/Tayanahtml/upload/Images/{item.SavePath}' alt='thumbnail' class='img-thumbnail' width='200px'/>", item.SavePath);
RadioButtonList.Items.Add(listItem);
}
}
}
DelImageBtn.Visible = false; //刪除鈕有選擇圖片時才顯示
}
🌵 SQL 語法的 WHERE 限制條件記得要改成下拉選單所選取的值,取值方法如下 : DropDownList1.SelectedValue;
👺 相簿管理相關功能請參考 Day12 文章,完成完整功能建立。
protected void DeletedModel(object sender, GridViewDeletedEventArgs e)
{
RadioButtonList.Items.Clear(); //清空圖片選項
DropDownList1.DataBind(); //刷新下拉選單
loadImageList(); //取得圖片選項
}
protected void UpdatedModel(object sender, GridViewUpdatedEventArgs e)
{
DropDownList1.DataBind(); //刷新下拉選單
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
RadioButtonList.Items.Clear(); //清空圖片選項
loadImageList(); //取得圖片選項
}
📢 本日實作算是之前實作的整合版,只要整合之前實作過的功能就可以完成,需要注意的是刪除遊艇型號時,要一併刪除型號相關的資料包含時計圖檔,而為了在刪除型號時一併刪除其它資料,所以要先取得刪除的遊艇型號,但如果取型號在一般的 OnRowDeleted 執行時,因為這時候型號已被刪除所以無法取得,在查了微軟官網的 GridView 事件後,發現可以把取型號的行為在刪除進行中的 OnRowDeleting 事件裡執行,並且執行相關資料刪除的行為,算是新的知識點。