Displaying Image Column in Bound TrueDbgrid

ComponentOne True DBGrid for WinForms is a set of robust, easy-to-use .NET grid controls that allows you to create complex bound and unbound grid applications quickly. When C1TrueDbGrid is bound to a data source which has an image column, neither the image column is shown in the grid nor does it get displayed in the grid designer. This creates a problem for the users who want to show the image column of the DataSource. This blog will help you in creating a bound C1TrueDbgrid displaying Images. In order to display the images, we need to add a C1DataColumn to the grid and then parse the Byte[] to an Image in FetchCellStyle event. We will begin with binding C1TrueDbGrid to a datasource. For simplicity, we are using Employees table of C1Nwind database which has a Photo column.

//Bind C1TrueDbGrid  
this.employeesTableAdapter.Connection = new OleDbConnection(GetConnectionString());  
this.employeesTableAdapter.Fill(this.c1NWindDataSet.Employees);  
c1TrueDBGrid1.DataSource = c1NWindDataSet.Tables[0];

The GetConnectionString() method here would return the path for the C1Nwind.mdb :

//Returns the connection string for the datasource  
static string GetConnectionString()  
{  
    string path = Environment.GetFolderPath(Environment.SpecialFolder.Personal)   @"\\ComponentOne Samples\\Common";  
    string conn = @"provider=microsoft.jet.oledb.4.0;data source={0}\\c1nwind.mdb;";  
    return string.Format(conn, path);  
}

To view images in the dataset, we need to make some changes in the grid as well. By default, the image column is not added to the C1TrueDbGrid. Hence, we need to add a C1DataColumn to the Photo column and set its DataField to Photo :

    // Add Picture Column  
    C1.Win.C1TrueDBGrid.C1DataColumn Col = new C1.Win.C1TrueDBGrid.C1DataColumn();  
    c1TrueDBGrid1.Columns.Insert(0, Col);  
    Col.Caption = "Photo";  
    Col.DataType = Type.GetType("Byte");  
    Col.DataField = "Photo";

When the Photo column is added, we need to define its position and then set the visibility to True. Furthermore, we need to set the custom cell styles for the new column, which is done by setting the FetchStyle property of the column to True and subscribing the FetchCellStyle event of the C1TrueDbGrid.

//Set the position of new "Photo" Column  
    C1.Win.C1TrueDBGrid.C1DisplayColumn dc;  
    dc = c1TrueDBGrid1.Splits[0].DisplayColumns["Photo"];  
    c1TrueDBGrid1.Splits[0].DisplayColumns.RemoveAt(c1TrueDBGrid1.Splits[0].DisplayColumns.IndexOf(dc));  
    c1TrueDBGrid1.Splits[0].DisplayColumns.Insert(0, dc);  
    dc.Visible = true;  
    dc.FetchStyle = true;  
    c1TrueDBGrid1.FetchCellStyle  = new C1.Win.C1TrueDBGrid.FetchCellStyleEventHandler(c1TrueDBGrid1_FetchCellStyle);

The grid's appearance can be modified by altering the size of the rows & columns and applying styles. The sizes of the rows and columns are changed in SetGridSize() method as :

//Sets the Default size for rows and columns in the Grid  
void SetGridSize()  
{  
    c1TrueDBGrid1.Splits[0].DisplayColumns["LastName"].Width = 70;  
    c1TrueDBGrid1.Splits[0].DisplayColumns["FirstName"].Width = 70;  
    c1TrueDBGrid1.Splits[0].DisplayColumns["Title"].Width = 150;  
    c1TrueDBGrid1.Splits[0].DisplayColumns["Notes"].Width = 320;  
    c1TrueDBGrid1.Splits[0].DisplayColumns["Notes"].Style.WrapText = true;  
    c1TrueDBGrid1.RowHeight = c1TrueDBGrid1.RowHeight * 8;  
}

The styles for C1TrueDbGrid are set in SetGridStyles() method. We will set the VisualStyle for the Grid and set AlternatingRows property to True to apply different styles for alternating rows. The styles for different rows are defined in the Styles property, where we can set BackColor, Gradients, and even images to the rows. The code for SetGridStyles() method is as follows :

//Sets the C1TrueDbGrid VisualStyle  
void SetGridStyles()  
{  
    c1TrueDBGrid1.VisualStyle = C1.Win.C1TrueDBGrid.VisualStyle.Office2010Blue;  
    c1TrueDBGrid1.AlternatingRows = true;  
    //Set EvenRow Style  
    c1TrueDBGrid1.Styles["EvenRow"].BackColor= Color.LightBlue;  
    c1TrueDBGrid1.Styles["EvenRow"].BackColor2= SystemColors.GradientInactiveCaption;  
    c1TrueDBGrid1.Styles["EvenRow"].GradientMode = C1.Win.C1TrueDBGrid.GradientModeEnum.Vertical;  

    //Set the OddRow Style  
    c1TrueDBGrid1.Styles["OddRow"].BackColor = Color.Khaki;  
    c1TrueDBGrid1.Styles["OddRow"].BackColor2 = Color.Wheat;  
    c1TrueDBGrid1.Styles["OddRow"].GradientMode = C1.Win.C1TrueDBGrid.GradientModeEnum.Vertical;  
}

Finally, making all the changes above would require the following code, which we will add in the Form_Load event :

private void Form1_Load(object sender, EventArgs e)  
{  
    //Bind C1TrueDbGrid  
    this.employeesTableAdapter.Connection = new OleDbConnection(GetConnectionString());  
    this.employeesTableAdapter.Fill(this.c1NWindDataSet.Employees);  
    c1TrueDBGrid1.DataSource = c1NWindDataSet.Tables[0];  

    // Add Picture Column  
    C1.Win.C1TrueDBGrid.C1DataColumn Col = new C1.Win.C1TrueDBGrid.C1DataColumn();  
    c1TrueDBGrid1.Columns.Insert(0, Col);  
    Col.Caption = "Photo";  
    Col.DataType = Type.GetType("Byte");  
    Col.DataField = "Photo";  
    //Set the position of new "Photo" Column  
    C1.Win.C1TrueDBGrid.C1DisplayColumn dc;  
    dc = c1TrueDBGrid1.Splits[0].DisplayColumns["Photo"];  
    c1TrueDBGrid1.Splits[0].DisplayColumns.RemoveAt(c1TrueDBGrid1.Splits[0].DisplayColumns.IndexOf(dc));  
    c1TrueDBGrid1.Splits[0].DisplayColumns.Insert(0, dc);  
    dc.Visible = true;  
    dc.FetchStyle = true;  
    c1TrueDBGrid1.FetchCellStyle  = new C1.Win.C1TrueDBGrid.FetchCellStyleEventHandler(c1TrueDBGrid1_FetchCellStyle);  

    //Set Grid Size  
    SetGridSize();  

    //Set the Grid styles  
    SetGridStyles();  
}

If we run the application now a formatted grid will become present, but we will notice that the text is shown in the Photo column instead of images. For this, we need to handle the FetchCellStyle event to change the Byte[] of the image column to Images. In this event we will parse the image column of the grid by converting each cell into an individual image object. This image object is then assigned to the ForeGroundImage of the e.Cell and then set its position by setting the ForeGroundPicturePosition property:

//Displays the cells as Image in Photo column  
private void c1TrueDBGrid1_FetchCellStyle(object sender, C1.Win.C1TrueDBGrid.FetchCellStyleEventArgs e)  
{  
    C1NWindDataSet.EmployeesRow row = c1NWindDataSet.Tables[0].Rows[c1TrueDBGrid1.RowBookmark(e.Row)] as C1NWindDataSet.EmployeesRow;  
    //C1NWindDataSet2.CategoriesRow row = c1TrueDBGrid1[e.Row] as C1NWindDataSet2.CategoriesRow;  
    e.CellStyle.ForegroundImage = GetImageFromByteArray(row.Photo);  
    e.CellStyle.ForeGroundPicturePosition = C1.Win.C1TrueDBGrid.ForeGroundPicturePositionEnum.PictureOnly;  
}

The GetImageFromByteArray() method is a subroutine to convert the Byte[] array to Bitmap images :

//Returns the Image  
private Image GetImageFromByteArray(byte[] picData)  
{  
    if (picData == null) return null;  

    // is this is an embedded object?  
    int bmData = (picData[0] == 0x15 && picData[1] == 0x1c) ? 78 : 0;  

    // load the picture  
    Image img = null;  
    try  
    {  
        System.IO.MemoryStream ms = new System.IO.MemoryStream(picData, bmData, picData.Length - bmData);  
        img = Image.FromStream(ms);  
    }  
    catch { }  

    // return what we got  
    return img;  
}

With this, we will have a bound C1TrueDbGrid with an image column.

GrapeCity

GrapeCity Developer Tools
comments powered by Disqus