Programmaticaly adding and populating an image column on a datagridview

I once made the mistake to solve the wish to have an image column in a datagridview by adding a VARBINARY field to the underlying database, and binding that column to the datagridview. Although the technique worked in the sense that it actualy does show the image that is now present in each and every row in your table, it’s needless to say that the performance and storage waste hit is horrible on large tables.

In this article i provide two better ways to add an image to a datagridview. The first code sample does this by manupilating the datagridview after the base data has been bound to it. The second code sample modifies the datatable *before* it is bound to the gridview, and then provides the data from the database server and the localy added image data to the datagridview.

The code sample below shows an efficient way to handle this scenario, by executing the next steps:
- A datatable with the data wanted on the gridview is retrieved from the AdventureWorks database
- The resulting table is bound to the datagridview (you can of course use any DataTable for this)
- A new column in added to the gridview, of type DataGridViewImageColumn
- The new column is moved to the very first position
- A loop iterates all the rows in the grid, and loads an image from the resources based on another column’s value

The result is that the images are only stored once in the project’s resources as it should be, and are efficiently bound to the grid at runtime. The resulting view is shown below.

using System;
using System.Windows.Forms;
using System.Data.SqlClient;

namespace WindowsFormsApplication1
{
  public partial class Form1 : Form
{
public Form1()
{
  InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{

  // Get a datatable from the database, we'll use the saleslt.customer
  // table from the adventureworks database
  string sConString = Properties.Settings.Default.ConString;
  using (var oCmd = new SqlCommand("select * from saleslt.customer"))
  {
    var oTable = NHC.Data.LibSQL.GetDataTableFromCommand(oCmd, sConString);
    dataGridView1.DataSource = oTable;
  }

  // Add the new image column to the grid
  var oIndicator = new DataGridViewImageColumn { Name = "Image" };
  dataGridView1.Columns.Add(oIndicator);

  // Move the new image column to the front of the grid
  dataGridView1.Columns["Image"].DisplayIndex = 0;

  // Place images in the column according to a value in another cell
  // We will use the "title" column from the adventureworks customers table.
  //
  // "red" and "green" are two JPG format images sized 24x24 pixels that
  // are preloaded into the local project resources.
  foreach (DataGridViewRow oRow in dataGridView1.Rows)
  {
    if (oRow.Cells["Title"].Value.ToString() == "Ms.")
  {
  oRow.Cells["Image"].Value = Properties.Resources.red;
  }
  else
  {
    oRow.Cells["Image"].Value = Properties.Resources.green;
  }

}

}
}
}

Code sample 2, Adding an image into a byte[] field in a new column in the datatable *before* binding to the datagridview


using System;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Data;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{

// Get a datatable from the database, we'll use the saleslt.customer
// table from the adventureworks database
string sConString = Properties.Settings.Default.ConString;
using (var oCmd = new SqlCommand("select * from saleslt.customer"))
{
var oTable = NHC.Data.LibSQL.GetDataTableFromCommand(oCmd, sConString);

// Add a Byte[] column to hold the images to the source data table
oTable.Columns.Add("Image", Type.GetType("System.Byte[]"));

// Move the column to the beginnen of the table
oTable.Columns["Image"].SetOrdinal(0);

// Loop the datatable to add the correct images based on the title field
foreach (DataRow oRow in oTable.Rows)
{

// Retrieve the correct bitmap for the row
Bitmap oImage;
if (oRow["Title"].ToString() == "Ms.")
{
oImage = Properties.Resources.red;
}
else
{
oImage = Properties.Resources.green;
}

// Convert to bitmap to a memorystream, and the memorystream into a byte[] array
using (var oStream = new MemoryStream())
{
oImage.Save(oStream, ImageFormat.Jpeg);
oRow["Image"] = oStream.ToArray();
}

}

// Bind the datatable to the grid
dataGridView1.DataSource = oTable;
}

}

}
}

If you want to try this exact sample out you will need to download and add the NHC.DLL file to your project, which provides (amongst other things) the GetDataTableFromCommand routine that will execute an arbitrary sql command and return the results as a datatable. [ NHC ]

Leave a Reply

*