=x= 🌵 建立後台相簿管理并使用 JSON 格式储存多个图片的路径。
📌 这个页面的作法是自己想出来的方式,结合想到的画面跟目前会使用的技能,可能并非常规见到的作法,主要是在思考 C# 阵列无法在宣告後变更长度,但是由於需要一个可以增删,用於储存图片名称的功能,在查找资料时查到可以用 List<T> 来存 JSON 资料,於是想办法做出想要的功能,大致的介面可以参考下图。
('[]')
<h6>Upload Horizontal Group Image :</h6>
<div class="input-group my-3">
<asp:FileUpload ID="imageUploadH" runat="server" class="btn btn-outline-primary btn-block" AllowMultiple="True" />
<asp:Button ID="UploadHBtn" runat="server" Text="Upload" class="btn btn-primary" OnClick="UploadHBtn_Click" />
</div>
<h6>Horizontal Image List :</h6>
<asp:RadioButtonList ID="RadioButtonListH" runat="server" class="my-3 mx-auto" AutoPostBack="True" OnSelectedIndexChanged="RadioButtonListH_SelectedIndexChanged" CellPadding="10" RepeatColumns="2" RepeatDirection="Horizontal"></asp:RadioButtonList>
<asp:Button ID="DelHImageBtn" 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" />
🌵 FileUpload 控制项的 AllowMultiple
设为 "True" 可以选择复数档案。
🌵 RadioButtonList 控制项的 RepeatDirection
可设定选项排版为直式或横式。
🌵 RadioButtonList 控制项的 RepeatColumns
可设定超过几个选项就进行换行。
// JSON 资料 Horizontal Image
public class ImageNameH
{
public string SaveName { get; set; }
}
loadImageHList();
方法//宣告全域 List<T> 可用 Add 依序添加资料
private List<ImageNameH> saveNameListH = new List<ImageNameH>();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack) {
loadImageHList();
}
}
private void loadImageHList()
{
//连线资料库取出资料
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
string sqlLoad = "SELECT certificatHorizontalImgJSON FROM Company WHERE id = 1";
SqlCommand command = new SqlCommand(sqlLoad, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.Read()) {
string loadJson = reader["certificatHorizontalImgJSON"].ToString();
//反序列化JSON格式
saveNameListH = JsonConvert.DeserializeObject<List<ImageNameH>>(loadJson);
}
connection.Close();
//可以改成用 ?.Count 来判断不是 Null 後才执行 .Count 避免错误
if (saveNameListH?.Count > 0) {
//逐一取出 JSON 的每笔资料
foreach (var item in saveNameListH) {
//将 RadioButtonList 选项内容改为图片格式,值设为档案名称
ListItem listItem = new ListItem($"<img src='/Tayanahtml/images/{item.SaveName}' alt='thumbnail' class='img-thumbnail' width='230px'/>", item.SaveName);
//加入图片选项
RadioButtonListH.Items.Add(listItem);
}
}
DelHImageBtn.Visible = false; //删除钮有选择图片时才显示
}
protected void UploadVBtn_Click(object sender, EventArgs e)
{
//有选择档案才执行
if (imageUploadV.HasFile) {
//先读取资料库原有资料
loadImageVList();
string savePath = Server.MapPath("~/Tayanahtml/images/");
//添加图档资料
//逐一读取选择的图片档案
foreach (HttpPostedFile postedFile in imageUploadV.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];
//在图片名称前加入 temp 标示并储存图片档案
postedFile.SaveAs(savePath + "temp" + fileName);
//新增 JSON 资料
saveNameListV.Add(new ImageNameV { SaveName = fileName });
//使用 NetVips 套件进行压缩图档
//判断储存的原始图片宽度是否大於设定宽度的 2 倍
var img = NetVips.Image.NewFromFile(savePath + "temp" + fileName);
if (img.Width > 214 * 2) {
//产生原使图片一半大小的新图片
var newImg = img.Resize(0.5);
//如果新图片宽度还是大於原始图片设定宽度的 2 倍就持续缩减
while (newImg.Width > 214 * 2) {
newImg = newImg.Resize(0.5);
}
//储存正式名称的新图片
newImg.WriteToFile(savePath + fileName);
}
else {
postedFile.SaveAs(savePath + fileName);
}
//删除原始图片
File.Delete(savePath + "temp" + fileName);
}
//更新新增後的图片名称 JSON 存入资料库
string fileNameJsonStr = JsonConvert.SerializeObject(saveNameListV);
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
string sql = "UPDATE Company SET certificatVerticalImgJSON = @fileNameJsonStr WHERE id = 1";
SqlCommand command = new SqlCommand(sql, connection);
command.Parameters.AddWithValue("@fileNameJsonStr", fileNameJsonStr);
connection.Open();
command.ExecuteNonQuery();
connection.Close();
//渲染画面
RadioButtonListV.Items.Clear();
loadImageVList();
}
}
👀 HttpPostedFile 类别官网参考 : HttpPostedFile 类别
👀 档案上传功能参考 : FileUpload好难使唤只好动手自己来
protected void RadioButtonListH_SelectedIndexChanged(object sender, EventArgs e)
{
//显示删除按钮
DelHImageBtn.Visible = true;
}
MaintainScrollPositionOnPostback="True"
可以让画面刷新後维持在原位置,而不会跑到最上方。
protected void DelHImageBtn_Click(object sender, EventArgs e)
{
//先读取资料库原有资料
loadImageHList();
//取得选取项目的值
string selHImageStr = RadioButtonListH.SelectedValue;
//删除图片档案
string savePath = Server.MapPath("~/Tayanahtml/images/");
File.Delete(savePath + selHImageStr);
//逐一比对原始资料 List<saveNameListH> 中的档案名称
for (int i = 0; i < saveNameListH.Count; i++) {
//与删除的选项相同名称
if (saveNameListH[i].SaveName.Equals(selHImageStr)) {
//移除 List 中同名的资料
saveNameListH.RemoveAt(i);
}
}
//更新删除後的图片名称 JSON 存入资料库
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
string saveNameJsonStr = JsonConvert.SerializeObject(saveNameListH);
string sql = "UPDATE Company SET certificatHorizontalImgJSON = @saveNameJsonStr WHERE id = 1";
SqlCommand command = new SqlCommand(sql, connection);
command.Parameters.AddWithValue("@saveNameJsonStr", saveNameJsonStr);
connection.Open();
command.ExecuteNonQuery();
connection.Close();
//渲染画面
RadioButtonListH.Items.Clear();
loadImageHList();
}
📢 制作时 List<T> 会需要放到全域的原因,是因为 PostBack 时资料会被清掉,而其它方法也会需要用到,所以放到该页後置程序码的全域,并且把读资料库资料这个方法独立出来,在进行其它关联事件时会先去读资料,这样才不会只存到新的资料,旧的资料反而被洗掉,而压缩图片应该算本页的彩蛋,压缩的方法是自己想的,可能有更高效的作法,目前图片存法最大会接近需求的 2 倍,另外判断有无同名档案的方法,一开始是做跟资料库比对,但发现这样逻辑不对,因为如果其它页面有上传同名档案,这样原本该页用的图片就会被盖掉,应该直接比对放档案的资料夹才对。
>>: [Day22] Rust 直接使用资料库语法操作资料库 (Part1)
tags: 2021铁人赛 React 前一篇提到的导览列的各个按钮,点击之後会跳到不同的页面,每个...
终於到了第30天了,对於第一次参加iThome铁人赛的我而言觉得有点不真实呀,可以发表这篇文章有和想...
如果为了履历好看放上参与度不高的专案、不够熟悉的技术、不真实的自我介绍;遇上老练的面试官,你将会血...
前言 昨天讲完了最基础的 atomic的资讯,了解了 atomic可以保护某个变数的资料正确性,当有...
终於来到最後一篇了!不经不觉已经写了三十篇文章。我们由 Ktor client 接驳 API 一直讲...