C# : List image reset after close app - c#

I'm using VS2013 to develop an windows form application with SQL Server database.
I have a column in database table to store the image name :
In my application, I creat a button to select image from my computer and save that's image to application startup path :
private void buttonX1_Click(object sender, EventArgs e)
{
try
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "Image only. | *.jpg; *.jpeg; *png; *.gif;";
dlg.InitialDirectory = #"E:\";
dlg.Multiselect = false;
string a = null;
if (dlg.ShowDialog() == DialogResult.OK)
{
string[] tmp = dlg.FileNames;
foreach (string i in tmp)
{
FileInfo fi = new FileInfo(i);
string[] xxx = i.Split('\\');
string des = Application.StartupPath + #"\Images\" + xxx[xxx.Length - 1];
string desfolder = Application.StartupPath + #"\Images\";
imagename = xxx[xxx.Length - 1].ToString();
System.IO.Directory.CreateDirectory(desfolder);
File.Delete(des);
imageuploaded.Image = Image.FromFile(dlg.FileName);
//over.
fi.CopyTo(des);
imageList1.Images.Add(imagename, Image.FromFile(des));
//Process.Start("explorer.exe", desfolder);
}
MessageBox.Show("Thành công ");
}
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
}
That code will load the image from computer, save to folder "images" in startup path and add image to imagelist1, too.
After that, I have a button to insert imagename to "Images" column (in SQL server database).
I have this code to use imagelist for my grid :
public PrdMan()
{
InitializeComponent();
GridPanel panel = superGridControl1.PrimaryGrid;
GridColumn column = panel.Columns["image"];
column.EditorType = typeof(MyGridImageEditControl);
column.EditorParams = new object[] { imageList1, ImageSizeMode.Zoom };
//superGridControl1.PrimaryGrid.Columns[8].Visible = false;
//superGridControl1.PrimaryGrid.Columns[2].CellStyles = "dd/MM/yyyy";
//styleManager1.ManagerStyle = eStyle.Metro;
//
//this.Location = new Point(0, 0);
//this.Size = Screen.PrimaryScreen.WorkingArea.Size;
}
And code to load grid :
this.mPhamTableAdapter.Fill(this.beautyMaDataSet.MPham);
this.superGridControl1.PrimaryGrid.DataSource = this.beautyMaDataSet.MPham;
My problem is : When I load image, and insert it into database's "Images" columns : It's success and grid will display image. But When I close app (after published) or stop debug (in VS) then re-open ( or debug again). The grid will not display my image
even though the image was still in folder :
And imagelist have no image in list :
I don't know what is my problem. Can you support me how to :
1/ Add image from PC to startup path's folder using C# and save image name to SQL server (to bind image to grid).
2/ Bind image from startup path's folder to imagelist and use it.
Thanks for support.

I sense two problems in your code, maybe some of them cause your problem.
First, if you load a table to a DataGridView (or something else), and update the GridView with your new image, but not write back to the database manually, the modification will not save to database.
As you said,
After that, I have a button to insert imagename to "Images" column (in SQL server database). I have this code to use imagelist for my grid
I guess one reason of your problem may relative to here.
Second, you used a dialog to select an image and copy to path "APP\Images", and store name to database. How will you do when the user run you application next time? Load the table and get image names, and find those images from the path?
Please provide the relative codes to solve your problem.
BTW, if the database is local, off-line DB, and also you won't store too many records, you may consider store your image raw-data in DB, too. (I know some people do not recommend this way, but in my opinion, it's one way to solve your problem too.)

Related

how to save multiple image's from image list in data base then slide show them in a picture box in C# windows form application?

i tried to add pictures using openfiledialog into an image list then save it in my Ms Access data base and call it in another form to show them in picture box by slide through them using a timer control but when i try to add picture's using open file dialog i get this error
An unhandled exception of type 'System.OutOfMemoryException' occurred in System.Drawing.dll
Additional information: Out of memory.
here is my code
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)
{
imgltargetpic.Images.Add(Image.FromFile(picture));//error is here
}
}
}
also if it's possible tell me with what format i can save the imagelist data in my data base i know the codes i just want to know what space should i open in my data base to save the data ( the format of imagelist output data)
here is the code for those who need to learn how to add the data into data base
OleDbConnection con = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Target.accdb");//this addres here is based on where you save your data base
OleDbCommand cmd = new OleDbCommand();
cmd.CommandText = "insert into tablename(tablefieldname,tablefieldname,...)values('" + textboxName.Text + "','" + textboxfamily.Text + "')";
cmd.Connection = con;
con.Open();
cmd.ExecuteNonQuery();
con.Close();
Update's : first of all the error ;; An unhandled exception of type 'System.OutOfMemoryException' occurred in System.Drawing.dll Additional information: Out of memory. in my problem was because the image i was choosing was corrupted !! for clarity i want to show the saved image data from data base in my c# windows form application in a picture box and the reason I'm choosing an image list is because i want to choose multiple image's and then slide show them using timer in a picture box for that i have already wrote the code to show it to the user before saving it in the data base here is the code :
int selectedpic = 0;
private void timerpicslide_Tick(object sender, EventArgs e)
{
picTargetchoose.Image = imgltargetpic.Images[selectedpic];
if (selectedpic == imgltargetpic.Images.Count -1)
{
selectedpic = 0;
}
else
{
selectedpic++;
}
}
i used the timer to select the picture's in the image list one by one every time the timer ticks (remember to start the timer when you add the picture's) now the problem is i cant call the saved data into my image list from data base and show it to the user using picture box here is the code I'm using :
private void cmbTarget_SelectedIndexChanged(object sender, EventArgs e)
{
con.Open();
OleDbDataAdapter da = new OleDbDataAdapter("select * from targetInfo where targetName like '" + cmbTarget.SelectedItem.ToString() + "%'", con);
DataTable dt = new DataTable();
da.Fill(dt);
dgvtargetview.DataSource = dt;
imglpicshow.Images.Add(Image.FromFile(dgvtargetview.CurrentRow.Cells[3].Value.ToString())); // where the problem lies
}
image list takes binary data i have saved the data in OLE Object format in my data base the way our friend #Albert D. Kallal suggested in the answer but now i cant take out of data base and put it in the image list to do the process .
thanks for your time!
Well, one would assume if you going to save the raw binary file in Access? Then the image control probably can figure out the format, but this suggests that you should ALSO at least have another column that saves the file name with extension.
And I would at least spend a cup of coffee time being REALLY sure you want to store the file in the database as opposed to in a folder, and then ONLY save the path name to the folder in the database table.
The reason for above are many, but this means:
If you ever want to adopt say sql server, then the data migration becomes very easy.
For any web based software - again having a path to a folder with images is VERY much less hassle and work.
Users can with great easy "copy files out" of that folder, search for file names in that folder, and use + launch their favorite picture editor and viewing software. If you tuck away that file inside of the database, then you quite much lose use of any and all picture editors, and even picture organization and picture slide show software etc. And it makes it difficult for any other software to use such pictures.
Also, it is not clear if you are wishing to display the pictures in c# applcation, or that you want the pictures to display say in a access form? So this issue should be made clear here.
As noted, you want to save the filename with extension, since if you ever need to pull pictures out of the db, then you need the file extension (unless say you only ever allow one picture type to be saved).
You CAN use the oleDB type column in the Access db, or use memo. (but, if you save as binary into memo type column, then you need a do a string covert into byte[] BEFORE you shove into the image control.
So, I used oleDB type, and my database is this:
DO KEEP in mind, we are not at all using the oleDB format that Access uses. This choice is really simple a binary data blob.
The images without wee bit of code in VBA/MS-Access can be displayed, but I'm assume we display and using in c# + a winform.
Ok, so say a form like this - real simple:
So, at top, we browse to a file - select it
This code:
private void cmdBrowseFile_Click(object sender, EventArgs e)
{
OpenFileDialog MyFile = new OpenFileDialog();
MyFile.ShowDialog();
if (MyFile.FileNames.Length > 0)
{
txtFile.Text = MyFile.FileName;
txtFileName.Text = Path.GetFileName(txtFile.Text);
ShowPicFile(MyFile.FileName);
}
}
void ShowPicFile(string sFile)
{
pictureBox1.Image = ByteToImage(File.ReadAllBytes(sFile));
}
public static Bitmap ByteToImage(byte[] blob)
{
Bitmap image;
using (MemoryStream stream = new MemoryStream(blob))
image = new Bitmap(stream);
return image;
}
So, if we browse to file - we display (not saved to db).
Say like this:
So, I take JUST the file name, shove into lower right box and then hit save to db
And it will add/save to db. That code is this:
private void cmdSave_Click(object sender, EventArgs e)
{
// save picture as bytes to DB
byte[] fData = File.ReadAllBytes(txtFile.Text);
string strSQL =
#"INSERT INTO MyPictures (FileName, PictureData)
VALUES(#File, #Data)";
OleDbCommand cmdSQL = new OleDbCommand(strSQL);
cmdSQL.Parameters.Add("#File", OleDbType.VarWChar).Value = txtFileName.Text;
cmdSQL.Parameters.Add("#Data", OleDbType.Binary).Value = fData;
MyRstP(cmdSQL, false);
// display in grid
cmdSQL.CommandText = "SELECT ID, FileName FROM MyPIctures";
cmdSQL.Parameters.Clear();
dataGridView1.DataSource = MyRstP(cmdSQL);
MessageBox.Show("saved");
}
And now the new row appears in our grid. I can click on any row, then click show from DB. that code is this:
private void cmdShow_Click(object sender, EventArgs e)
{
int pk = (int)dataGridView1.CurrentRow.Cells[0].Value;
OleDbCommand cmdSQL =
new OleDbCommand("SELECT ID, PictureData FROM MyPictures WHERE ID = #ID");
cmdSQL.Parameters.Add("#ID", OleDbType.Integer).Value = pk;
DataRow OneRow = MyRstP(cmdSQL).Rows[0];
pictureBox1.Image = ByteToImage((byte[])OneRow["PictureData"]);
}
And my helper routines
DataTable MyRstP(OleDbCommand cmdSQL, bool ReturnsData = true)
{
DataTable rstData = new DataTable();
using (OleDbConnection conn = new OleDbConnection(Properties.Settings.Default.AccessDB))
{
using (cmdSQL)
{
cmdSQL.Connection = conn;
conn.Open();
if (ReturnsData)
rstData.Load(cmdSQL.ExecuteReader());
else
cmdSQL.ExecuteNonQuery();
}
}
return rstData;
}
and
public static Bitmap ByteToImage(byte[] blob)
{
Bitmap image;
using (MemoryStream stream = new MemoryStream(blob))
image = new Bitmap(stream);
return image;
}

Why does openfiledialog say 'Path does not exist' or 'Catastrophic Error' after selecting a file for the second time?

I am trying to make a file display. When the user selects a file, it displays the icon of the file in the window. When I select the Google Chrome icon and click on 'OK' in the openfiledialog, the intended result happens. (see pictures below)
However, when I select another icon (e.g Word), it gives me the error 'Path does not exist'.
(see pictures below)
If I select another file (e.g File Explorer) it gives me 'Catastrophic Error' (see pictures below)
For some reason, this problem only happens with shortcut files. For other files like .txt files or .exe files, this problem does not occur.
Here is my code (Add_Item is the name of the button)
private void AddItem_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
if (openFileDialog.ShowDialog() == true)
{
foreach (String myfile in openFileDialog.FileNames)
{
// here myfile represent your selected file name
//get filename
string filename = System.IO.Path.GetFileName(myfile);
//TODO: Create settings
Icon icon1 = System.Drawing.Icon.ExtractAssociatedIcon(myfile);
Bitmap icon = icon1.ToBitmap();
System.Windows.Controls.Image image = new System.Windows.Controls.Image();
image.Source = BitmapToImageSource(icon);
Tiles.Children.Add(image);
}
}
}
Can anyone help me?
Thanks
Alright, {DeferenceLinks = false} fixed my problem.

How to fix ListView.LargeImageList showing images twice

I am working on a piece of software, which compares memes and helps users organize memes on their computer. As a part of this I am using Windows.Forms to build a UI. This UI lets the user add folders to be checked for images, which can be compared to a set of known meme templates.
My issue arises when I try to show the user the found images. To do this I am using a ListView and the property LargeImageList to contain a tuple of the image and the name of the image file.
Here is the piece of code in question:
private void button1_Click(object sender, EventArgs e)
{
int i = 0;
var ic = new ImageCollection();
var fbd = new FolderBrowserDialog();
fbd.Description = "Select meme folder or image.";
if (fbd.ShowDialog() == DialogResult.OK)
{
string[] files = Directory.GetFiles(fbd.SelectedPath);
foreach (var file in files)
{
if (!ic.CheckIfImage(file)) continue;
imageList1.Images.Add(Image.FromFile(file));
}
foreach (var file in files)
{
listView1.Items.Add($"{Path.GetFileNameWithoutExtension(file)}", i++);
}
}
}
This is an example of what the user sees when they first load in a folder. When the user tries to load in another folder this happens. It shows the images from the first folder, with the names of the image files from the second folder.
Does anyone know a fix for this issue? I have tried a variety of options in order to get around the issue. All from trying to clear the ImageList used to contain the images, to trying my hand at controlling when the ListView updates. None of this has worked. I have also tried googling the issue, but with no luck of finding a fix.
Thank you in advance.
If you want to show the content of a single folder at the time, then dispose of the objects in your ImageList.
If you instead want to show the content of more than one folder, you need to specify the new index of the image added. You're instead adding a new Item in the ListView using the same index reference:
int i = 0;
//(...)
listView1.Items.Add($"{Path.GetFileNameWithoutExtension(file)}", i++);
The indexer (i) always starts from 0, thus the ListView Item will use the images in your Imagelist starting from the Image at Index[0] each time. The new images won't ever be shown.
You can use the ImageList.Images.Count value, representing the number of Images already added to the ImageList, as base and increment the indexer starting from this value:
private void button1_Click(object sender, EventArgs e)
{
int i = imageList1.Images.Count;
var ic = new ImageCollection();
var fbd = new FolderBrowserDialog();
fbd.Description = "Select meme folder or image.";
if (fbd.ShowDialog() == DialogResult.OK)
{
foreach (var file in Directory.GetFiles(fbd.SelectedPath))
{
if (!ic.CheckIfImage(file)) continue;
imageList1.Images.Add(new Bitmap(file, true));
listView1.Items.Add($"{Path.GetFileNameWithoutExtension(file)}", i++);
}
}
}
If you allow to remove an Image from the ListView, you should also remove it from the ImageList: this implies that you need to re-index all the ListView Items starting from the Item that follows the one removed.
Remember to dispose of the Images you remove from the ImageList.

How do I get the Bitmap name when I click the image in datagridview?

I am trying to click on an image in a datagridview and then write its image/file name into a textbox so I can access this from elsewhere.
First I try just a small app to make sure I can make it all work. A Dialog contains the dataviewgrid and I put a bitmap into it as below:
public ChooseFormat()
{
InitializeComponent();
dataGridView1[0,0].Value = new Bitmap(#"C:\a\eggs\grid_app\grid_app\bin\Debug\graphics\1L5HQ60.bmp");
}
Now I click on the image but all the things I have tried I cannot get hold of the file name. The closest I get is below but this returns "System.Drawing.Bitmap" and not the file name. I am sure this must just be a tweak here to make it work but I have tried teh few things I know and nothing is working.
void DataGridView1CellContentClick(object sender, DataGridViewCellEventArgs e)
{
txtbx_choice.Text = dataGridView1[0,0].Value.ToString();
}
Drilling into the cells's data in the debugger doesn't bring up any info on the source of it. Maybe I have overlooked something..
One simple solution is to store the filename in the cell's Tag property:
string fileName = #"C:\a\eggs\grid_app\grid_app\bin\Debug\graphics\1L5HQ60.bmp";
dataGridView1[0,0].Value = new Bitmap(fileName );
dataGridView1[0,0].Tag = fileName ;
Now you can always access it:
string displayedFile = dataGridView1[0, someRow].Tag.ToString();
I have placed a Picture Box on the same form and this how I am displaying the ImageColumn's data (an Image ) in picture box
pictureBox1.Image = (Image)dataGridView1[0, 0].Value;

How to detect whether pictureBox successfully displayed the image or not?

I have a pictureBox that loads an image directly from the internet. The image can change dynamically and is specified by the user in a textBox that has a TextChanged event that changes the image in pictureBox to the URL in the textBox. When user clicks the submit button, the image URL is saved in the database. But before saving I want to validate the image, that whether the image displayed successfully or the error image is displayed in place of it. So how can I validate this?
You can use the LoadComplete event to see when it has changed, and if the eventArg's error is null (successful) or not null (fail).
void pictureBox1_LoadCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
MessageBox.Show(e.Error.ToString());
}
this.pictureBox1.Validated += new EventHandler(pictureBox1_Validated);
this.pictureBox1.ImageLocation = this.textBox1.Text;
-
Edit: Just saw Dips' comment, did not use that link but is same means to answer this.
Place the code below in the function where you are retrieving the path of image from textBox ,be sure to place it before you do anything else on that path;
string path = "Path to image";
Bitmap bmp;//To validate the Image.
try
{
bmp = new Bitmap(path);//Create a Bitmap object from the given path.
if (bmp != null)
{
pictureBox1.Load(path);//Display the image to the user.
//Now it's safe to store the image path in the database,
//because we have validated it.
bmp.Dispose();//Dispose the Bitmap object to free occupied resources.
//Place you database related code here which uses the path we just validated.
}
}
catch (ArgumentException)
{
MessageBox.Show("The specified image file is invalid.");
//Show error image in PictureBox.
//(pictureBox1.Image="Path to error image").
//Don't store image path,its invalid.
}
catch (FileNotFoundException)
{
MessageBox.Show("The path to image is invalid.");
//Show error image in PictureBox.
//(pictureBox1.Image="Path to error image").
//Don't store image path,its invalid.
}
When you've done this you can place your code where I've shown the comment //Place your database....This ensures that the file path and image is validated before anything else uses them.`This method also checks if the image file is actually an image and not a .txt or .exe with its extension changed to .jpg or any other image format,as you've mentioned in your comments you need to check if the path actually points to an image file.
You can the extend the exception handling mechanism if you need something more than displaying a MessageBox with error information.One more thing that is worth to be mentioned is that,before you display any image or do anything you will have to check if the url is valid one,to simplify this step you can try to download the file(it can be anything - an image,an executable,a text file or at least a web page,when it has been downloaded pass the path to that file(relative to filesystem) to this function.
Hope it works for you.
Suppose Pic1 is name of your control. To validate then you can use simply,
if(pic1.ImageLocation.Trim().Length>4) // > 4 since a shortest valid image
file will be a.png or something
similar; length= 5
{
if(validExtensions(pic1.ImageLocation)
{
//then put the path to database
}
}
Updated
//Mehod to valid image extensions
private bool validExtensions(string url)
{
var imgs = new []{".jpg",".gif",".png",".bmp",".jpeg"};
var ext = System.IO.Path.GetFileExtention(url); // see the correct method
in intellisense
if(imgs.Contains(ext)
return false;
}
Update 2
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.jfif, *.png) | *.jpg; *.jpeg; *.jpe; *.jfif; *.png";
dialog.InitialDirectory = #"C:\";
dialog.Title = "Please select an image file to encrypt.";
if (dialog.ShowDialog() == DialogResult.OK)
{
//Encrypt the selected file. I'll do this later. :)
}

Categories