[ Team LiB ] |
Recipe 7.13 Loading a Windows PictureBox with Images Stored by Access as OLE ObjectsProblemYou need to display images from a Microsoft Access database in a PictureBox control. SolutionStrip the OLE image header that Microsoft Access adds to the image. The sample code contains six event handlers:
The C# code is shown in Example 7-29. Example 7-29. File: DisplayMsAccessImageForm.csusing System; using System.Configuration; using System.Drawing; using System.Windows.Forms; using System.IO; using System.Data; using System.Data.OleDb; private const int MSACCESSIMAGEOFFSET = 78; private DataSet ds; private OleDbDataAdapter da; private BindingManagerBase bm; // . . . private void DisplayMsAccessImageForm_Load(object sender, System.EventArgs e) { // Create the DataSet. ds = new DataSet( ); // Create the DataAdapter and retrieve the Categories table. String selectCommand = "SELECT CategoryID, CategoryName, Description FROM Categories"; da = new OleDbDataAdapter(selectCommand, ConfigurationSettings.AppSettings["MsAccess_ConnectString"]); da.FillSchema(ds, SchemaType.Source, "Categories"); da.Fill(ds, "Categories"); // Bind table fields to controls. categoryIdTextBox.DataBindings.Add("Text", ds, "Categories.CategoryID"); categoryNameTextBox.DataBindings.Add("Text", ds, "Categories.CategoryName"); descriptionTextBox.DataBindings.Add("Text", ds, "Categories.Description"); // Get the binding manager base for the parent table. bm = BindingContext[ds, "Categories"]; // Update the image in response to each record reposition. bm.PositionChanged += new EventHandler(bm_PositionChanged); // Update the display for the first record. bm_PositionChanged(null, null); } private void bm_PositionChanged(Object sender, EventArgs e) { // Refresh the photo displayed when the current record changes. // Get the new CategoryID using the BindingManager. int categoryId = (int)ds.Tables["Categories"].Rows[bm.Position]["CategoryID"]; // Create a connection. OleDbConnection conn = new OleDbConnection( ConfigurationSettings.AppSettings["MsAccess_ConnectString"]); // Create a command to retrieve the category photo. String sqlText = "SELECT Picture FROM Categories WHERE CategoryID=" + categoryId; OleDbCommand cmd = new OleDbCommand(sqlText, conn); // Retrieve the image from the database. conn.Open( ); Byte[] image = (Byte[])cmd.ExecuteScalar( ); // Write to a stream removing the image header. MemoryStream ms = new MemoryStream( ); ms.Write(image, MSACCESSIMAGEOFFSET, image.Length - MSACCESSIMAGEOFFSET); conn.Close( ); // Load the image into the PictureBox from the stream. picturePictureBox.Image = Image.FromStream(ms); ms.Close( ); } private void moveFirstButton_Click(object sender, System.EventArgs e) { bm.Position = 0; } private void movePreviousButton_Click(object sender, System.EventArgs e) { bm.Position -= 1; } private void moveNextButton_Click(object sender, System.EventArgs e) { bm.Position += 1; } private void moveLastButton_Click(object sender, System.EventArgs e) { bm.Position = bm.Count - 1; } DiscussionThe Windows Forms PictureBox control displays bitmap, JPEG, metafile, or icon images. Microsoft Access stores an image as an OLE object that wraps the actual image. This means that the image is prefixed with a variable-length header that must be stripped off to retrieve the image. The length of this header for bitmap images stored in the Northwind sample database is 78 bytes. In the solution, the image stored as a BLOB in the database is retrieved into a Byte array. The Byte array is copied into a MemoryStream object using an overload of the Write( ) method that allows the 78 byte offset to be specified. The static FromStream( ) method of the Image class creates an Image object from the MemoryStream that is loaded into the PictureBox. |
[ Team LiB ] |