=x= 🌵 建立 Specification Manager - Content Page 後台页面。
📌 从 Yachts 页面的 Specification 分页内容里可以观察到 :
🧠 下半区块 - 新增游艇共用的特殊部位标题及列表。
🧠 左上区块 - 型号下拉选单 + Layout & Deck Plan Image 组图上传。
🧠 右上区块 - 游艇部位标题下拉选单 + 部位细项细节添加。
🌵 型号下拉选单用来决定是哪个型号的资料。
🌵 细节标题下拉选单资料来源为上方下半区块的表格。
🧠 细项规格分别对应游艇型号及游艇部位标题的 ID,并设定串联删除。
🌵 Layout & Deck Plan Image 组图为图档档名 JSON 资料存在 Yachts 资料表内。
🌵 游艇部位标题因为是共用所以独立一张表。
🧠 型号下拉选单设定直接使用精灵设定并将值设为 id,页面设计参考如下
<h6>Yacht Model :</h6>
<asp:DropDownList ID="DListModel" runat="server" DataSourceID="SqlDataSource1" DataTextField="yachtModel" DataValueField="id" AutoPostBack="True" Width="100%" Font-Bold="True" class="btn btn-outline-primary dropdown-toggle" OnSelectedIndexChanged="DListModel_SelectedIndexChanged"></asp:DropDownList>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:TayanaYachtConnectionString %>" SelectCommand="SELECT [yachtModel], [id] FROM [Yachts]"></asp:SqlDataSource>
<hr />
<h6>Layout & Deck Plan Image :</h6>
<h6><span class="badge badge-pill badge-warning text-dark">* The maximum upload size at once is 10MB !</span></h6>
<div class="input-group my-3">
<asp:FileUpload ID="imageUpload" runat="server" class="btn btn-outline-primary btn-block" AllowMultiple="True" />
<asp:Button ID="UploadImgBtn" runat="server" Text="Upload" class="btn btn-primary" OnClick="UploadImgBtn_Click"/>
</div>
<hr />
<h6>Group Image List :</h6>
<asp:RadioButtonList ID="RadioButtonListImg" runat="server" class="my-3 mx-auto" AutoPostBack="True" OnSelectedIndexChanged="RadioButtonListImg_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="DelImageBtn_Click"/>
🧠 部位标题下拉选单设定直接使用精灵设定并将值设为 id,页面设计参考如下
<h6>Detail Title :</h6>
<asp:DropDownList ID="DListDetailTitle" runat="server" DataSourceID="SqlDataSource2" DataTextField="detailTitleSort" DataValueField="id" AutoPostBack="True" Width="100%" Font-Bold="True" class="btn btn-outline-primary dropdown-toggle" OnSelectedIndexChanged="DListDetailTitle_SelectedIndexChanged"></asp:DropDownList>
<asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:TayanaYachtConnectionString %>" SelectCommand="SELECT [detailTitleSort], [id] FROM [DetailTitleSort]"></asp:SqlDataSource>
<hr />
<h6>Add Detail :</h6>
<asp:TextBox ID="TboxDetail" runat="server" type="text" class="form-control" placeholder="Enter detail text" TextMode="MultiLine" Height="100px"></asp:TextBox>
<asp:Button ID="BtnAddDetail" runat="server" Text="Add Detail" class="btn btn-outline-primary btn-block mt-3" OnClick="BtnAddDetail_Click"/>
<hr />
<h6>Detail List :</h6>
<asp:RadioButtonList ID="RadioButtonListDetail" runat="server" class="my-3 mx-auto" AutoPostBack="True" RepeatDirection="Vertical" OnSelectedIndexChanged="RadioButtonListD_SelectedIndexChanged" Width="100%"></asp:RadioButtonList>
<asp:Button ID="BtnDelDetail" runat="server" Text="Delete Detail" type="button" class="btn btn-danger btn-sm" OnClientClick="return confirm('Are you sure you want to delete?')" Visible="False" OnClick="BtnDelDetail_Click"/>
🧠 结合共用标题输入功能与新增按钮的页面设计参考如下
<h6>Add New Title :</h6>
<div class="input-group mb-3">
<asp:TextBox ID="TBoxAddNewTitle" runat="server" type="text" class="form-control" placeholder="Enter new title" ></asp:TextBox>
<div class="input-group-append">
<asp:Button ID="BtnAddNewTitle" runat="server" Text="Add" class="btn btn-outline-primary btn-block" OnClick="BtnAddNewTitle_Click" />
</div>
</div>
🧠 共用标题的 GridView 表格页面设计参考如下
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="id" DataSourceID="SqlDataSource3" BackColor="White" BorderColor="#CCCCCC" BorderStyle="None" BorderWidth="1px" CellPadding="3" Width="100%" OnRowDeleted="DeltedTitle" OnRowUpdated="UpdatedTitle">
<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 Number" InsertVisible="False" ReadOnly="True" SortExpression="id" >
<ItemStyle HorizontalAlign="Center" />
</asp:BoundField>
<asp:BoundField DataField="detailTitleSort" HeaderText="Detail Title" SortExpression="detailTitleSort" />
<asp:BoundField DataField="initDate" HeaderText="Creation Date" SortExpression="initDate" ReadOnly="True" InsertVisible="False" />
<asp:TemplateField HeaderText="Delete" ShowHeader="False">
<ItemTemplate>
<asp:LinkButton ID="BtnDeleteTitle" 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="SqlDataSource3" runat="server" ConnectionString="<%$ ConnectionStrings:TayanaYachtConnectionString %>" SelectCommand="SELECT * FROM [DetailTitleSort]" DeleteCommand="DELETE FROM [DetailTitleSort] WHERE [id] = @id" UpdateCommand="UPDATE [DetailTitleSort] SET [detailTitleSort] = @detailTitleSort WHERE [id] = @id">
<DeleteParameters>
<asp:Parameter Name="id" Type="Int32" />
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="detailTitleSort" Type="String" />
<asp:Parameter Name="id" Type="Int32" />
</UpdateParameters>
</asp:SqlDataSource>
//宣告 List<T> 方便用 Add 依序添加资料
private List<ImagePath> savePathList = new List<ImagePath>();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack) {
DListModel.DataBind(); //先取得型号预设选取值
DListDetailTitle.DataBind(); //先取得细节标题预设选取值
loadImageList(); //取得 Layout 组图
loadDetailList(); //取得标题细节
}
}
#region Group Image List
private void loadImageList()
{
//依型号取得组图图片资料
string selectModel_id = DListModel.SelectedValue;
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
string sqlLoad = "SELECT layoutDeckPlanImgPathJSON FROM Yachts WHERE id = @selectModel_id";
SqlCommand command = new SqlCommand(sqlLoad, connection);
command.Parameters.AddWithValue("@selectModel_id", selectModel_id);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.Read()) {
//将特殊符号解码
string loadJson = HttpUtility.HtmlDecode(reader["layoutDeckPlanImgPathJSON"].ToString());
//反序列化JSON格式
savePathList = JsonConvert.DeserializeObject<List<ImagePath>>(loadJson);
}
connection.Close();
//渲染图片选项
if (savePathList?.Count > 0) {
foreach (var item in savePathList) {
ListItem listItem = new ListItem($"<img src='/Tayanahtml/upload/Images/{item.SavePath}' alt='thumbnail' class='img-thumbnail' width='250px'/>", item.SavePath);
RadioButtonListImg.Items.Add(listItem);
}
}
DelImageBtn.Visible = false; //删除钮有选择图片时才显示
}
protected void UploadImgBtn_Click(object sender, EventArgs e)
{
//有选择档案才执行
if (imageUpload.HasFile) {
//取得上传档案大小 (限制 10MB)
int fileSize = imageUpload.PostedFile.ContentLength;
if (fileSize < 1024 * 1000 * 10) {
//先读取资料库原有资料
loadImageList();
string savePath = Server.MapPath("~/Tayanahtml/upload/Images/");
//添加图档资料
foreach (HttpPostedFile postedFile in imageUpload.PostedFiles) {
//储存图片档案及图片名称
//检查专案资料夹内有无同名档案,有同名就加流水号
DirectoryInfo directoryInfo = new DirectoryInfo(savePath);
string fileName = postedFile.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];
postedFile.SaveAs(savePath + "temp" + fileName);
savePathList.Add(new ImagePath { SavePath = fileName });
//压缩图档
var image = NetVips.Image.NewFromFile(savePath + "temp" + fileName);
if (image.Width > 672 * 2) {
var newImg = image.Resize(0.5);
while (newImg.Width > 672 * 2) {
newImg = newImg.Resize(0.5);
}
newImg.WriteToFile(savePath + fileName);
}
else {
postedFile.SaveAs(savePath + fileName);
}
File.Delete(savePath + "temp" + fileName);
}
//依游艇型号更新资料
string selectModel_id = DListModel.SelectedValue;
//将 List<T> 资料转为 JSON 格式字串
string savePathJsonStr = JsonConvert.SerializeObject(savePathList);
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
string sql = "UPDATE Yachts SET layoutDeckPlanImgPathJSON = @layoutDeckPlanImgPathJSON WHERE id = @selectModel_id";
SqlCommand command = new SqlCommand(sql, connection);
command.Parameters.AddWithValue("@layoutDeckPlanImgPathJSON", savePathJsonStr);
command.Parameters.AddWithValue("@selectModel_id", selectModel_id);
connection.Open();
command.ExecuteNonQuery();
connection.Close();
//渲染画面
RadioButtonListImg.Items.Clear();
loadImageList();
}
else {
Response.Write("<script>alert('*The maximum upload size is 10MB!');</script>");
}
}
}
// Layout 图片 JSON 资料
public class ImagePath
{
public string SavePath { get; set; }
}
protected void RadioButtonListImg_SelectedIndexChanged(object sender, EventArgs e)
{
DelImageBtn.Visible = true;
}
protected void DelImageBtn_Click(object sender, EventArgs e)
{
//依选取项目删除 List<T> 资料
loadImageList(); //先取得 List<T> 资料
string selImageStr = RadioButtonListImg.SelectedValue;
string savePath = Server.MapPath("~/Tayanahtml/upload/Images/");
File.Delete(savePath + selImageStr);
for (int i = 0; i < savePathList.Count; i++) {
if (savePathList[i].SavePath.Equals(selImageStr)) {
savePathList.RemoveAt(i);
}
}
//将 List<T> 资料转为 JSON 格式字串
string savePathJsonStr = JsonConvert.SerializeObject(savePathList);
string selectModel_id = DListModel.SelectedValue;
//依选取型号更新图档资料
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
string sql = "UPDATE Yachts SET layoutDeckPlanImgPathJSON = @layoutDeckPlanImgPathJSON WHERE id = @selectModel_id";
SqlCommand command = new SqlCommand(sql, connection);
command.Parameters.AddWithValue("@layoutDeckPlanImgPathJSON", savePathJsonStr);
command.Parameters.AddWithValue("@selectModel_id", selectModel_id);
connection.Open();
command.ExecuteNonQuery();
connection.Close();
//渲染画面
RadioButtonListImg.Items.Clear();
loadImageList();
}
#endregion
#region
及#endregion
,因为前面相簿建立好後就可以整组沿用。
private void loadDetailList()
{
//取得 Model 代表 id
string selectModel_id = DListModel.SelectedValue;
//取得 Title 代表 id
string selectTitle_id = DListDetailTitle.SelectedValue;
//依游艇型号 id 及标题 id 取得 Detail
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
string sql = "SELECT detail FROM Specification WHERE yachtModel_ID = @selectModel_id AND detailTitleSort_ID = @selectTitle_id";
SqlCommand command = new SqlCommand(sql, connection);
command.Parameters.AddWithValue("@selectModel_id", selectModel_id);
command.Parameters.AddWithValue("@selectTitle_id", selectTitle_id);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read()) {
string detail = reader["detail"].ToString();
//将转成字元实体的编码转回 HTML 标签语法渲染
ListItem listItem = new ListItem(HttpUtility.HtmlDecode(detail), detail);
RadioButtonListDetail.Items.Add(listItem);
}
connection.Close();
BtnDelDetail.Visible = false; //删除钮有选择项目时才显示
}
🌵 读取资料条件设为游艇型号 ID + 部位标题 ID。
🌵 这里需要进行 HtmlDecode 是因为细项资料包含 <br>
换行标签。
protected void BtnAddNewTitle_Click(object sender, EventArgs e)
{
//取得输入标题字串
string newTitleStr = TBoxAddNewTitle.Text;
//1.连线资料库
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
//2.sql语法
string sql = "INSERT INTO DetailTitleSort (detailTitleSort) VALUES(@newTitleStr)";
//3.创建command物件
SqlCommand command = new SqlCommand(sql, connection);
//4.参数化
command.Parameters.AddWithValue("@newTitleStr", newTitleStr);
//5.资料库连线开启
connection.Open();
//6.执行sql (新增删除修改)
command.ExecuteNonQuery(); //单纯执行无回传值
//7.资料库关闭
connection.Close();
//画面渲染
GridView1.DataBind();
DListDetailTitle.DataBind();
//下拉选单改为选取最新项
DListDetailTitle.SelectedIndex = DListDetailTitle.Items.Count - 1;
//清空输入栏位
TBoxAddNewTitle.Text = "";
}
protected void DeltedTitle(object sender, GridViewDeletedEventArgs e)
{
//刷新下拉选单
DListDetailTitle.DataBind();
//刷新细节项目
RadioButtonListDetail.Items.Clear();
RadioButtonListDetail.DataBind();
loadDetailList();
}
protected void UpdatedTitle(object sender, GridViewUpdatedEventArgs e)
{
//刷新下拉选单
DListDetailTitle.DataBind();
//刷新细节项目
RadioButtonListDetail.Items.Clear();
RadioButtonListDetail.DataBind();
loadDetailList();
}
protected void BtnAddDetail_Click(object sender, EventArgs e)
{
//取得新增 Detail
string newDetailStr = TboxDetail.Text;
//将换行跳脱字元改成 HTML 换行标签
newDetailStr = newDetailStr.Replace("\r\n", "<br>");
//依取得下拉选项的值 (id) 存入 Detail 资料
string selectModel_id = DListModel.SelectedValue;
string selectTitle_id = DListDetailTitle.SelectedValue;
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
string sql = "INSERT INTO Specification (yachtModel_ID, detailTitleSort_ID, detail) VALUES (@selectModel_id, @selectTitle_id, @detail)";
SqlCommand command = new SqlCommand(sql, connection);
command.Parameters.AddWithValue("@selectModel_id", selectModel_id);
command.Parameters.AddWithValue("@selectTitle_id", selectTitle_id);
//特殊符号要转成字元实体才能正常存进资料库
command.Parameters.AddWithValue("@detail", HttpUtility.HtmlEncode(newDetailStr));
connection.Open();
command.ExecuteNonQuery();
connection.Close();
//将改成 HTML 换行标签资料加入选项渲染画面
ListItem listItem = new ListItem(newDetailStr, newDetailStr);
RadioButtonListDetail.Items.Add(listItem);
TboxDetail.Text = "";
}
🌵 这里需要将换行的跳脱字元r\n
换成<br>
换行标签。
🌵 想看跳脱字元,可以安装 Notepad++,将文字贴到记事本用 Notepad++开启。
protected void BtnDelDetail_Click(object sender, EventArgs e)
{
//依选取资料删除 Detail 资料
string selectModel_id = DListModel.SelectedValue;
string selectTitle_id = DListDetailTitle.SelectedValue;
string selectDetailStr = RadioButtonListDetail.SelectedValue;
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
string sql = "DELETE FROM Specification WHERE yachtModel_ID = @selectModel_id AND detailTitleSort_ID = @selectTitle_id AND detail = @selectDetailStr";
SqlCommand command = new SqlCommand(sql, connection);
command.Parameters.AddWithValue("@selectModel_id", selectModel_id);
command.Parameters.AddWithValue("@selectTitle_id", selectTitle_id);
command.Parameters.AddWithValue("@selectDetailStr", selectDetailStr);
connection.Open();
command.ExecuteNonQuery();
connection.Close();
//渲染画面
RadioButtonListDetail.Items.Clear();
loadDetailList();
}
protected void RadioButtonListD_SelectedIndexChanged(object sender, EventArgs e)
{
//显示细节项目删除按钮
BtnDelDetail.Visible = true;
}
protected void DListDetailTitle_SelectedIndexChanged(object sender, EventArgs e)
{
//刷新细节选项
RadioButtonListDetail.Items.Clear();
loadDetailList();
}
protected void DListModel_SelectedIndexChanged(object sender, EventArgs e)
{
//刷新全部选项
RadioButtonListImg.Items.Clear();
RadioButtonListDetail.Items.Clear();
loadImageList();
loadDetailList();
}
📢 本日後台页面,因为主要内容为细项规格,但由於细项规格是由两个下拉选单所决定,在取值跟画面的更新时,要特别注意是否刷新,另外就是多行文字记得要将跳脱字元,转换为 HTML 标签,这样才能正常呈现换行的效果。
<<: Day 27 : Python - 什麽是列表推导式?又该如何将它和if、if-else一起做使用?
有一些演算法是在图(graph)上操作,我们可以先想一些实际的例子,例如: 开车的时候,使用导航系统...
上一篇说到了,AR宠物的部分,如果我们真的能用程序模拟出动物的习性、动作,那是不是代表说我们也能模拟...
Hashicorp Vault: Path limit 在Vault里,当enable一个Secre...
上一篇我们的基因体时代-AI, Data和生物资讯 Day20-注释基因资讯的BED档案格式和bed...
大家好,我是YIYI,今天我要来制作HOMEPAGE中MONTH与TODAY的切换以及右下角的加号点...