Control Rendering in Print Document
Often times we want to display a control, rendered on a Windows form, in a C1PrintDocument. However, being that there is no direct method to achieve this, we can follow the approach mentioned in this blog. The idea is to capture the control's state as an image object and then render it the same in a Print Document. The implementation, though, is something that makes this worth reading. We will use C1Flexgrid control with a bound image column and then render it on a C1PrintDocument.
Step 1: Display Bound Images in C1FlexGrid
Step One is carried out by binding C1FlexGrid with a datasource. For simplicity we are using Category table of C1Nwind database. //Binding C1FlexGrid categoriesTableAdapter.Connection = new OleDbConnection(GetConnectionString()); categoriesTableAdapter.Fill(this.c1NWindDataSet.Categories); _flex.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 rendered within a flexgrid column, it is necessary to make some changes. By default, the visibility of the image column is set as false. Set the visibility of Picture column to True. Furthermore, we need to set the custom cell drawing, which is done by setting the DrawMode property of the grid to OwnerDraw and subscribing the OwnerDrawCell event. Finally, making all the preceding revisions would require the following code which we have added in the Form_Load event :
private void Form1_Load(object sender, EventArgs e)
{
//Binding C1FlexGrid
categoriesTableAdapter.Connection = new OleDbConnection(GetConnectionString());
categoriesTableAdapter.Fill(this.c1NWindDataSet.Categories);
_flex.DataSource = c1NWindDataSet.Tables[0];
//Displaying Picture Column and Attaching a OwnerDrawCell Event to _flex
_flex.Cols["Picture"].Visible = true;
_flex.DrawMode = C1.Win.C1FlexGrid.DrawModeEnum.OwnerDraw;
\_flex.OwnerDrawCell =new C1.Win.C1FlexGrid.OwnerDrawCellEventHandler(\_flex_OwnerDrawCell);
// initialize styles
\_flex.Styles.Normal.Margins.Left = \_flex.Styles.Normal.Margins.Right = 0;
_flex.Styles.Normal.TextAlign = C1.Win.C1FlexGrid.TextAlignEnum.LeftTop;
_flex.Styles.Fixed.TextAlign = C1.Win.C1FlexGrid.TextAlignEnum.LeftCenter;
// make rows taller to show images
int hei = _flex.Rows.DefaultSize;
_flex.Rows.DefaultSize = hei * 4;
_flex.Rows[0].Height = hei;
}
Within the OwnerDrawCell event we parse the image column of the grid by converting each cell into an individual image object :
//Handles Custom Cell Drawing to display bound images
private void \_flex\_OwnerDrawCell(object sender, C1.Win.C1FlexGrid.OwnerDrawCellEventArgs e)
{
// "Picture" is an image stored in a blob (byte[])
if (_flex.Cols[e.Col].Name == "Picture")
{
// try loading from mdb
e.Image = LoadImage(_flex[e.Row, e.Col] as byte[]);
// if we got an image, blank text
if (e.Image != null) e.Text = null;
}
}
The LoadImage() method is a subroutine to convert the Byte[] array to Bitmap images :
// load bitmap image stored in blob DB field
// this assumes the image was stored as an OLE "package"
// (this is the format used by Access)
static Image LoadImage(byte[] picData)
{
// make sure this is an embedded object
const int bmData = 78;
if (picData == null || picData.Length < bmData 2) return null;
if (picData[0] != 0x15 || picData[1] != 0x1c) return null;
// we only handle bitmaps for now
if (picData[bmData] != 'B' || picData[bmData 1] != 'M') return null;
// load the picture
Image img = null;
try
{
MemoryStream ms = new MemoryStream(picData, bmData, picData.Length - bmData);
img = Image.FromStream(ms);
}
catch { }
// return what we got
return img;
}
At the end of step one, we have a bound Flexgrid with an image column.
Step 2: Capture an image of C1FlexGrid
Now we will capture the image of C1FlexGrid using a GetControlImage() method. This is a simple method that uses the ClientRectangle of the control and the DrawToBitmap() method of Control class to convert it into a bitmap image with a zoom-like speed.
// Method to convert C1FlexGrid into an image
static Image GetControlImage(Control ctl, float zoom)
{
// get image
Rectangle rc = ctl.ClientRectangle;
Bitmap bmp = new Bitmap(rc.Width, rc.Height);
ctl.DrawToBitmap(bmp, rc);
// apply zoom
if (zoom != 1)
{
Size newSize = Size.Round(new SizeF(bmp.Width * zoom, bmp.Height * zoom));
bmp = new Bitmap(bmp, newSize);
}
// return image
return bmp;
}
We will use this method when opening a form containing C1PrintPreviewControl :
PreviewForm frm = new PreviewForm(GetControlImage(_flex, 1));
frm.ShowDialog();
Step 3: Render Captured Image in C1PrintDocument
The last step is to render the captured image in a C1PrintDocunment. We will add 2 objects to the document -- RenderText and RenderImage. RenderText renders text on the PrintDocument whereas RenderImage renders the captured C1FlexGrid image. We also define the default unit and page margins for the document in this step. The code should look as follows :
private void PreviewForm_Load(object sender, EventArgs e)
{
//PrintDocument for C1PrintPreviewControl
C1PrintDocument doc = new C1PrintDocument();
doc.DefaultUnit = UnitTypeEnum.Inch;
doc.PageLayout.PageSettings.TopMargin = 0.5;
doc.PageLayout.PageSettings.LeftMargin = 0.5;
doc.PageLayout.PageSettings.RightMargin = 0.5;
doc.PageLayout.PageSettings.BottomMargin = 0.5;
//Renders text
RenderText rt = new RenderText();
rt.Text = "C1FlexGrid Image Rendering on C1PrintDocument";
doc.Body.Children.Add(rt);
//Renders C1FlexGrid control image
RenderImage ri = new RenderImage();
ri.Image = img;
ri.Width = doc.PageLayout.PageSettings.Width.Value-1;
doc.Body.Children.Add(ri);
c1PrintPreviewControl1.Document = doc;
}
When we run the application, C1FlexGrid is displayed on the form. Click on the Render To PrintDocument button and the flexgrid will appear on the C1PrintPreviewControl. Download Sample