=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 倍,另外判斷有無同名檔案的方法,一開始是做跟資料庫比對,但發現這樣邏輯不對,因為如果其它頁面有上傳同名檔案,這樣原本該頁用的圖片就會被蓋掉,應該直接比對放檔案的資料夾才對。