Introduction
If you have a database which contains images - even if they are thumbnails - then loading them all on startup can take serious amount of time. For example, a recent application had a Picture class, with an Id, a Description, a thumbnail image, and a location for the full image all stored in a database. On startup, I needed to load the Pictures from the DB, so I could tie them together with the other classes. With around 1000 100x100 pixel jpg thumbnails in the DB, it was taking 13 to 15 seconds to load them all at startup - a silly amount of time.
So, instead, I changed it to on demand loading - which means that the time to load the image (from file or database) is deferred until the image itself is actually needed. Since this is generally as a result of user actions, we are then talking in terms of human reaction speeds, and 1000th of 15 seconds (plus the extra overhead of a DB connection setup) doesn't make any difference, people just don't notice the delay.
Using the code
It's pretty easy to do. Assuming your Picture class is written properly, you already have a Image property for the thumbnail:
public Image Thumbnail {get; private set;}
All you have to do is replace the auto-implemented backing field with a private version, and move the database access code into the property:
private Image thumbnail = null;
public Image Thumbnail
{
get
{
if (thumbnail == null)
{
using (SqlConnection con = new SqlConnection(GenericData.DBConnection))
{
con.Open();
using (SqlCommand cmd = new SqlCommand("SELECT Thumbnail FROM Images WHERE Id=@ID", con))
{
cmd.Parameters.AddWithValue("@ID", Id);
SqlDataReader r = cmd.ExecuteReader();
if (r.Read())
{
MemoryStream ms = new MemoryStream((byte[])r["Thumbnail"]);
thumbnail = GenericData.GetImage(ms);
}
}
}
}
return thumbnail;
}
private set
{
thumbnail = value;
}
}
The GetImage
method just creates an image from a Stream without requiring the stream to be open for the lifetime of the Image:
public static Image GetImage(Stream stream)
{
Image img;
using (Image temp = Image.FromStream(stream))
{
img = new Bitmap(temp);
}
return img;
}
Points of Interest
This is something I do quite often, I just wish I'd remember to do it in the first place each time...
History
Original version.