SaveAs and delete same time c# [duplicate] - c#

I am trying to delete local copy(on the computer) of an image file once uploaded using file dialog. It throws The process cannot access the file 'C:\Documents and Settings\username\My Documents\My Pictures\1220.bmp' because it is being used by another process.
private void _btnImportPhoto_Click(object sender, RoutedEventArgs e)
{
//user clicked import/change photo, open file dialog to browse for photo
System.Windows.Forms.OpenFileDialog fileDialog = new System.Windows.Forms.OpenFileDialog();
fileDialog.Multiselect = false;
fileDialog.Filter = ResourceFile.PhotoFileTypes;
if (fileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
FilePath = fileDialog.FileName;
FilePathCopy = fileDialog.FileName;
string safeFilePath = fileDialog.SafeFileName;
Bitmap bitmap = new Bitmap(FilePath);
CurrentPhoto = bitmap;
Bitmap bitmap1 = new Bitmap(FilePathCopy); //A copy to save when if delete local copy is chosen
m_PhotoCopy = bitmap1;
FileSystem.DeleteFile(FilePath);
}
_btnSave.IsEnabled = _btnCancel.IsEnabled = true;
}
}
Please let me know how to work around this issue.
Thanks.

you need to dispose of the bitmap object try doing this. As this will dispose of the bitmap object as soon as it leaves the using context { }
using (Bitmap bitmap1 = new Bitmap(FilePathCopy))
{
//do all bitmap stuff in here
}

First I see
Bitmap bitmap = new Bitmap(FilePath);
CurrentPhoto = bitmap;
Where CurrentPhoto I presume some global variable that you want hold.
This, instead throws and exception:
FileSystem.DeleteFile(FilePath);
Cause image file at FilePath is actually CurrentPhoto. What you can do.
1) If use of CurrentPhoto has any sense inside this function, do what you want to do inside this function, and after dispose CurrentPhoto object, even in a way like #Bobby suggests (using block)
2) If you want to have it by the way, you can try to use Bitmap's Clone
method like this:
CurrentPhoto = bitmap.Clone();
and after call your:
bitmap.Dispose();
FileSystem.DeleteFile(FilePath);
Should work.

Try this...
http://www.lockergnome.com/blade/2006/11/28/windows-error-message-error-deleting-file-or-folder/
It will allow you to delete files or folder.

Related

C#,Winform - Setting arguments for Process class with Drawing.Image

I'm generating a picture in the picturebox
pictureBox1.Image = Image.FromStream(imageActions.GetImage(reader["ID_no"].ToString()));
It is working perfectly, but I am also creating an option for the user to edit it via any application (Let's example macromedia) So I created a button and did the thing.
private void button2_Click(object sender, EventArgs e)
{
Process photoViewer = new Process();
photoViewer.StartInfo.FileName = #"C:\Program Files\Macromedia\Fireworks 8\Fireworks.exe";
photoViewer.StartInfo.Arguments = ___________;
photoViewer.Start();
}
I understand that in the photoViewer.StartInfo.Arguments = you can put here the path of the image, but in my case. the image is stored in the Database as Image datatype. any ideas?
In order to load the image in an external application, you will first of all need to save it to the disk.
After the application has closed you will need to load the updated image to display to the user.
The Image property of the PictureBox control has a Save method you can call:
string tempFile = System.IO.Path.GetTempFileName();
pictureBox1.Image.Save(tempFile);
You can then pass the tempFile value as a parameter to the photoViewer process (I used MSPaint as a Proof of Concept):
Process photoViewer = new Process();
photoViewer.StartInfo.FileName = #"C:\Windows\System32\MSPaint.exe";
photoViewer.StartInfo.Arguments = tempFile;
photoViewer.EnableRaisingEvents = true;
photoViewer.Exited += photoViewer_Exited;
photoViewer.Start();
The two lines of photoViewer.EnableRaisingEvents = true and photoViewer.Exited += photoViewer_Exited; will tell your application when the photoViewer process exits, and this is a good place for you to load the image and display to your users.
private void photoViewer_Exited(object sender, EventArgs e)
{
pictureBox1.Image = Image.FromFile(tempFile);
}
Note: string tempFile will need to be a class member variable so it can be accessed in the two functions.

Editting the picturebox image using external editor and loading the new image

I try to open an external editor during Runtime and edit an image which is currently is set to a PictureBox, edit the image and update the image after closing the editor.
For this, I have a simple c# windows application with a PictureBox two Button one to load PictureBox Image from file and another to edit the image using MS Paint.
Here is the code:
public partial class Form1 : Form
{
string myImagePath = #"C:\temp\bt_logo.png";
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
pictureBox1.Image = Image.FromFile(myImagePath);
}
private void button2_Click(object sender, EventArgs e)
{
System.Diagnostics.ProcessStartInfo launchEditor = new System.Diagnostics.ProcessStartInfo();
launchEditor.FileName = "mspaint";
launchEditor.Arguments = myImagePath;
launchEditor.UseShellExecute = true;
System.Diagnostics.Process.Start(launchEditor);
}
}
The Editor is openned successfully but the changes cannot be saved because of access problem:
Any idea how to solve this problem?
EDIT1:
In order to stop accessing the image when the editor is open, I modified the code of button2_Click() as follows:
pictureBox1.Image = null;
System.Diagnostics.ProcessStartInfo launchEditor = new System.Diagnostics.ProcessStartInfo();
launchEditor.FileName = "mspaint";
launchEditor.Arguments = myImagePath;
launchEditor.UseShellExecute = true;
System.Diagnostics.Process.Start(launchEditor);
pictureBox1.Image = Image.FromFile(myImagePath);
same resault. As another try, I made a copy of the image, modified it and copied it to the original image,
System.IO.File.Copy(myImagePath, myImagePath_temp, true);
System.Diagnostics.ProcessStartInfo launchEditor = new System.Diagnostics.ProcessStartInfo();
launchEditor.FileName = "mspaint";
launchEditor.Arguments = myImagePath_temp;
launchEditor.UseShellExecute = true;
System.Diagnostics.Process.Start(launchEditor);
System.IO.File.Copy(myImagePath_temp, myImagePath, true);
the same resault!
This question is essentially a duplicate of
Open Image from file, then release lock?
Image.FromFile locks the file on disk, until the image variable in your code is disposed of. You should observe the accepted answer to that question above; it provides a way to load the image data from disk, copy it inside the memory of your program, and then release the lock on the file and use the copy of the bitmap data in your picturebox
You'll find an answer on how to load your image without it being locked in the file system. I'm writing an answer instead of a comment because I wanted to give a bit of further advice to the rest of the program
Take a look at the FileSystemWatcher class; Notification when a file changes?
you can use it to detect changes to your file so the picture box can be updated when the file is saved rather than when paint is quit- this will be easier than coding to detect the app closing

Disposing of image when using PictureBox

I'm working with a Winforms program that was written a while ago. I've come across some issues with it and I'm trying to optimize the way it handles some things but I'm running across some issues with disposing.
Below is what is currently implementing.
First, It starts with going through the files in the Pictures folder and copies them into a preview folder.
foreach (string s in files)
{
fileName = System.IO.Path.GetFileName(s);
destFile = System.IO.Path.Combine(path, fileName);
File.Copy(s, destFile, true);
}
Next, it opens a form via ShowDialog:
frmPreview frm = new frmPreview(FileNameArray, lblParcel.Text);
frm.ShowDialog();
Next, it goes to the Preview form and gets to this code:
try {
FlowLayoutPanel imagePanel = new FlowLayoutPanel();
if (System.IO.Directory.Exists(path))
{
folder = new DirectoryInfo(path);
foreach (FileInfo files in folder.GetFiles())
{
System.Diagnostics.Debug.Print(files.Extension);
if ((string.Equals(files.Extension, ".jpg", StringComparison.OrdinalIgnoreCase)) || (string.Equals(files.Extension, ".gif", StringComparison.OrdinalIgnoreCase)) || (string.Equals(files.Extension, ".png", StringComparison.OrdinalIgnoreCase)))
{
PictureBox image = new PictureBox();
image.Image = Image.FromFile(files.FullName);
image.SizeMode = PictureBoxSizeMode.Zoom;
image.Size = this.Size;
imagePanel.Controls.Add(image);
}
}
}
this.Controls.Add(imagePanel);
System.Threading.Thread.Sleep(0);
return;
}
catch
{
}
The code above basically takes all the photos, creates a PictureBox with each one, and adds the PictureBox to the FlowLayoutPanel to display in a window for previewing. Problem with this is that it does not dispose properly and gets caught up after trying to visit this preview window for the 3rd time (closing the window and opening it a second time works fine but creates a second process).
Lastly, It implements the following when the form closes.
private void frmPreview_FormClosed(object sender, FormClosedEventArgs e)
{
this.Dispose();
this.Close();
}
The error happens on the 3rd time the preview window is called, when the program goes through the foreach statement posted at the top.
The full line where it catches is:
File.Copy(s, destFile, true);
The process cannot access the file 'C:\Users\username\Pictures\Preview\image.jpg' because it is being used by another process.
I'm 99.9% sure it's because of the PictureBox and FlowLayoutPanel but I can't figure out what to do to fix it. I'd like to change as little as possible since this isn't my program and it will soon be rewritten completely. I mainly just need to temporarily fix the issue until we finish the big picture where this whole program will get scrapped.
I've found a couple posts that seem to be similar issues but none of the fixes have changed anything at all. Below are all the posts I looked into and trying implementing unsuccessfully:
file-copy-the-process-cannot-access-the-file
file-is-being-used-by-another-process
dispose-of-a-picturebox
Issue fixed after implementing the recommendation of #RezaAghaei. Changed the Preview form to this:
foreach (FileInfo files in folder.GetFiles())
{
System.Diagnostics.Debug.Print(files.Extension);
if ((string.Equals(files.Extension, ".jpg", StringComparison.OrdinalIgnoreCase)) || (string.Equals(files.Extension, ".gif", StringComparison.OrdinalIgnoreCase)) || (string.Equals(files.Extension, ".png", StringComparison.OrdinalIgnoreCase)))
{
using (var stream = new FileStream(files.FullName, FileMode.Open))
{
PictureBox image = new PictureBox();
image.Image = Image.FromStream(stream);
image.SizeMode = PictureBoxSizeMode.Zoom;
image.Size = this.Size;
imagePanel.Controls.Add(image);
}
}
}
I also improved the efficiency of the ShowDialog call by implementing a using block:
using (frmPreviewPhotos frm = new frmPreviewPhotos(NEWphotoFileNameArray, lblParcel.Text))
{
frm.ShowDialog();
}

Image box flickers after new image is loaded

So i have this code which for every string in the array it adds it the file path and uses it as the file path for the image box, this is the code:
private async void Button7_Click(object sender, RoutedEventArgs e)
{
string[] images = new string[] { "Star_00001.png", "Star_00002.png", "Star_00003.png", "Star_00004.png", "Star_00005.png", "Star_00006.png", "Star_00007.png", "Star_00008.png"};
string path = "Assets/Star/";
foreach(string file in images)
{
string thepath = Path.Combine(path,file);
await Task.Delay(46);
BitmapImage Image = new BitmapImage();
Image.UriSource = new Uri(this.BaseUri, thepath);
StarImage.Source = Image;
}
}
Now everytime the new image is loaded in to the StarImage, it flickers, as far as I know their is no way to stop this because it is the effect of loading a new image in the image box, however does anyone know any alternatives to stop this and give the effect of an animation?
I think some sort of buffering technique may reduce or eliminate the flickering problem you have.
I've never done this in c#, but essentially you draw to an image which is not yet visible referred to as the buffer, and then make it visible when the image is completely drawn.
This may help.
try this:
private async void Button7_Click(object sender, RoutedEventArgs e)
{
string[] images = new string[] { "Star_00001.png", "Star_00002.png", "Star_00003.png", "Star_00004.png", "Star_00005.png", "Star_00006.png", "Star_00007.png", "Star_00008.png" };
string path = "Assets/Star/";
foreach (string file in images)
{
string thepath = Path.Combine(path, file);
await Task.Delay(46);
BitmapImage Image = new BitmapImage();
Image.BeginInit();
Image.UriSource = new Uri(this.BaseUri, thepath);
Image.CacheOption = BitmapCacheOption.OnLoad;
Image.EndInit();
StarImage.Source = Image;
}
}
I've been racking my brains for months trying to solve this, and then I found this post. It helped me solve this! I can't understand for the life of me why Microsoft keeps changing the syntax to do things in windows.
How to set Background of a Button without flicker?

Showing animated gif in Winforms without locking the file

I'm trying to display images of various file types (including animated .gif files) in my Winforms application. I also have to be able to modify the files that are shown. (change the file name, delete them).
The problem is that a Picturebox locks the image file until the application is closed when using the normal way.
That means I can't do this:
private void Form1_Load(object sender, EventArgs e)
{
PictureBox pic = new PictureBox();
pic.Size = new Size(250, 250);
pic.Image = Image.FromFile("someImage.gif");
this.Controls.Add(pic);
//No use to call pic.Image = null or .Dispose of it
File.Delete("someImage.gif"); //throws exception
}
The workaround in the link above is as follows:
private void Form1_Load2(object sender, EventArgs e)
{
PictureBox pic = new PictureBox();
pic.Size = new Size(250, 250);
//using a FileStream
var fs = new System.IO.FileStream("someImage.gif", System.IO.FileMode.Open, System.IO.FileAccess.Read);
pic.Image = System.Drawing.Image.FromStream(fs);
fs.Close();
this.Controls.Add(pic);
pic.MouseClick += pic_MouseClick;
}
That works fine for normal image types, but it won't load animated .gifs, which is important to me. Trying to load one will make it look like this.
I've found a few other topics about it (this and this) but they're all about WPF and use BitmapImage. I've searched about how to use BitmapImage in a Winforms application, but haven't found anything apart from that it is supposed to somehow work.
I would like to stay with Winforms because I'm just getting used to it, but that's not a necessity.
To summarize: I need a way to show common image types (png, jpg, bmp, and animated gif) while still being able modify the file on the HDD. It is OK if that means unloading->modifying->reloading the file. I'd prefer Winforms, but other Frameworks would do.
Thanks for your help.
Edit: Another way I've tried
using (System.IO.FileStream fs = new System.IO.FileStream("E:\\Pics\\small.gif", System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
fs.CopyTo(ms);
pic.Image = Image.FromStream(ms);
}
But shows the same problem as the second example. The gif doesn't load.
Using a MemoryStream is indeed the right way to avoid the file lock. Which is a strong optimization btw, the lock is created by the memory-mapped file that the Image class uses to keep the pixel data out of the paging file. That matters a great deal when the bitmap is large. Hopefully not on an animated gif :)
A small mistake in your code snippet, you forgot to reset the stream back to the start of the data. Fix:
using (var fs = new System.IO.FileStream(...)) {
var ms = new System.IO.MemoryStream();
fs.CopyTo(ms);
ms.Position = 0; // <=== here
if (pic.Image != null) pic.Image.Dispose();
pic.Image = Image.FromStream(ms);
}
In case it needs to be said: do not dispose the memory stream. That causes very hard to diagnose random crashes later, pixel data is read lazily.
Essentialy you'll have to make a copy of the image file in your memory.
Pre .Net 4.0 (2.0,3.0,3.5) you'd have to create a FileStream and copy it to a MemoryStream and rewind it, as seen in another answer.
Since .Net 4.0 (4.0,4.5,...) Image.FromFile supports animated GIF's
If you work with .Net 4.0 or later following method will suffice:
Using System.IO, System.Drawing and System.Drawing.Imaging
private void Form1_Load(object sender, EventArgs e)
{
string szTarget = "C:\\someImage.gif";
PictureBox pic = new PictureBox();
pic.Dock = DockStyle.Fill;
Image img = Image.FromFile(szTarget); // Load image fromFile into Image object
MemoryStream mstr = new MemoryStream(); // Create a new MemoryStream
img.Save(mstr, ImageFormat.Gif); // Save Image to MemoryStream from Image object
pic.Image = Image.FromStream(mstr); // Load Image from MemoryStream into PictureBox
this.Controls.Add(pic);
img.Dispose(); // Dispose original Image object (fromFile)
// after this you should be able to delete/manipulate the file
File.Delete(szTarget);
}

Categories

Resources