C# WinForm:图片列表存Access库及轮播读取问题
问题解决指南
一、图片添加到ImageList的内存溢出问题
你已查明问题源于损坏图片,建议在代码中增加异常处理,避免单张损坏图片导致整个流程中断:
private void btnPicAdd_Click(object sender, EventArgs e) { ofdTargetPic.Filter = "Image File (*.Gif;*.jpg)|*.Gif;*.jpg"; ofdTargetPic.Title = "Add target picture"; ofdTargetPic.Multiselect = true; ofdTargetPic.FileName = string.Empty; DialogResult result = ofdTargetPic.ShowDialog(); if (result == DialogResult.OK) { picTargetchoose.SizeMode = PictureBoxSizeMode.StretchImage; foreach (var picture in ofdTargetPic.FileNames) { try { // 用using包裹Image,避免资源泄漏 using (Image img = Image.FromFile(picture)) { // 克隆图片后添加到ImageList,释放原文件锁 imgltargetpic.Images.Add(new Bitmap(img)); } } catch (Exception ex) { MessageBox.Show($"图片 {picture} 加载失败:{ex.Message}"); } } } }
补充:用new Bitmap(img)克隆图片,还能避免Image.FromFile锁定原文件的问题。
二、Access数据库存储图片的字段类型
存储图片二进制数据时,Access数据库字段类型设置为OLE Object即可,这部分你已经配置正确。注意入库时要将图片转为二进制流存储,而非文件路径。
三、从OLE Object字段读取图片到ImageList的正确代码
你当前代码错误地使用Image.FromFile,但数据库中存储的是二进制数据而非文件路径,修正后的读取代码如下:
private void cmbTarget_SelectedIndexChanged(object sender, EventArgs e) { // 清空现有ImageList,避免重复添加 imglpicshow.Images.Clear(); // 使用参数化查询,避免SQL注入风险 string sql = "select * from targetInfo where targetName like ?"; using (OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Target.accdb")) { using (OleDbDataAdapter da = new OleDbDataAdapter(sql, con)) { // 添加参数,处理模糊查询 da.SelectCommand.Parameters.AddWithValue("@targetName", $"{cmbTarget.SelectedItem.ToString()}%"); DataTable dt = new DataTable(); da.Fill(dt); dgvtargetview.DataSource = dt; // 遍历所有行的图片字段,添加到ImageList foreach (DataRow row in dt.Rows) { if (row[3] != DBNull.Value) { byte[] imgBytes = (byte[])row[3]; using (MemoryStream ms = new MemoryStream(imgBytes)) { // 从内存流加载图片并添加到ImageList imglpicshow.Images.Add(Image.FromStream(ms)); } } } } } // 重置轮播索引并启动Timer selectedpic = 0; if (imglpicshow.Images.Count > 0) { timerpicslide.Start(); // 显示第一张图片 picTargetchoose.Image = imglpicshow.Images[selectedpic]; } else { timerpicslide.Stop(); picTargetchoose.Image = null; } }
关键修正点:
- 用参数化查询替代SQL拼接,避免注入风险
- 从DataRow中读取
byte[]类型的二进制数据 - 通过
MemoryStream将二进制数据转为Image,再添加到ImageList - 处理DBNull情况,避免空值异常
四、轮播代码优化(可选)
原轮播代码可以简化为取模运算,逻辑更简洁:
int selectedpic = 0; private void timerpicslide_Tick(object sender, EventArgs e) { if (imglpicshow.Images.Count == 0) { timerpicslide.Stop(); return; } picTargetchoose.Image = imglpicshow.Images[selectedpic]; selectedpic = (selectedpic + 1) % imglpicshow.Images.Count; }
内容的提问来源于stack exchange,提问作者grafiyas
相关产品推荐
相关产品推荐

