I'm working in a WPF application where I show my images in two places which means the same image gets loaded in two places. In one of the place the image will be shown along with other few images in a slider where it will be able to edit and save. If there is no image available in the location I should be showing a separate image Image not found which is not editable.
When I started working on the functionality I got the Used by another process exception during edit and save. So after searching I came up with a solution and now at a rare time I get the Out of memory exception when I click the Next or Previous or First or Last in slider. The slider is just an Image control with 4 buttons. When the buttons are clicked the below method is called. I'm not sure if there is any memory leaks.
bool NoImage = true;
private static readonly object _syncRoot = new object();
private BitmapSource LoadImage(string path)
{
lock (_syncRoot) //lock the object so it doesn't get executed more than once at a time.
{
BitmapDecoder decoder = null;
try
{
//If the image is not found in the folder, then show the image not found.
if (!File.Exists(path) && (path != null))
{
System.Drawing.Bitmap ss = XXXX.Resources.ImageNotFound;
var stream = new System.IO.MemoryStream();
if (!File.Exists(Path.GetTempPath() + "ImageNotFound.jpg"))
{
FileStream file = new FileStream(Path.GetTempPath() + "ImageNotFound.jpg", FileMode.Create, FileAccess.Write);
ss.Save(stream, ImageFormat.Jpeg);
stream.Position = 0;
stream.WriteTo(file);
file.Close();
stream.Close();
}
path = Path.Combine(Path.GetTempPath(), "ImageNotFound.jpg");
NoImage = false;
}
else
{
if (!EnableForEdit)
NoImage = false;
else
NoImage = true;
}
if (!string.IsNullOrEmpty(path) && (!NoImage || File.Exists(path)))
{
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
{
decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
return decoder.Frames.FirstOrDefault();
}
else
return null;
}
catch (OutOfMemoryException ex)
{
MessageBox.Show("Insufficient memory to handle the process. Please try again later.", "Application alert");
return null;
}
catch (Exception ex)
{
// Error handling.
throw new ApplicationException(ex.Message);
}
finally
{
decoder = null;
GC.WaitForFullGCComplete(1000);
GC.Collect(0, GCCollectionMode.Forced);
}
}
}
<Image x:Name="viewImage" Grid.Row="2" Height="100" Width="135" Source="{Binding DisplayImage, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" />
If my approach is wrong, let me know where should I do the change or if there is any simpler way to do. Kindly help.
Note: The images which are loaded is above 5Mb