Display Multiple Clickable Images in C1Flexgrid for Winforms

C1FlexGrid control is a powerful, full-featured grid and provides all the basic and advanced features. It also exposes a certain method SetCellImage(), that gives users the ability to display an image in a grid cell. SetCellImage() method however, lets the user display only one image in a cell. There are occasions though, when one might need to display more than a single image in a particular cell/column. This article provides us with a way to implement this. Also, should the user somehow, become successful in displaying multiple images in a single cell, what if he needs to implement some logic in the event of a particular image being clicked? Say, there are three images A, B and C; and user needs a notification when any of those images is clicked. Here, we'll talk about this as well. Considering there's no other property/method to display multiple images in a cell, the only alternative is to draw them manually. And, there's no other event than 'OwnerDrawCell' that we may employ for this purpose. Take a look at the code given below :

c1FlexGrid1.DrawMode = C1.Win.C1FlexGrid.DrawModeEnum.OwnerDraw;  
c1FlexGrid1.OwnerDrawCell += (s1, e1) =>  
 if (e1.Col == 1 && e1.Row == 1)  
  //let the grid paint the background and border for the cell  
  e1.DrawCell(C1.Win.C1FlexGrid.DrawCellFlags.Background | C1.Win.C1FlexGrid.DrawCellFlags.Border);  

  //find text width  
  var width = (int)e1.Graphics.MeasureString(e1.Text, e1.Style.Font).Width;  

  //x-coordinate for each image  
  var img1_x = e1.Bounds.X + width - 10;  
  var img2\_x = img1\_x + img1.Width + 5;  
  var img3\_x = img2\_x + img2.Width + 5;  

  //location for each image  
  var img1\_loc = new Point(img1\_x, e1.Bounds.Y + img1.Height - 18);  
  var img2\_loc = new Point(img2\_x, e1.Bounds.Y + img1.Height - 18);  
  var img3\_loc = new Point(img3\_x, e1.Bounds.Y + img1.Height - 18);  

  //draw images at aforementioned points  
  e1.Graphics.DrawImage(img1, img1_loc);  
  e1.Graphics.DrawImage(img2, img2_loc);  
  e1.Graphics.DrawImage(img3, img3_loc);  

  //draw text  
  e1.Graphics.DrawString(e1.Text, e1.Style.Font, Brushes.Black, e1.Bounds.Location);  
  e1.Handled = true;  

Here, I should point out that the user needs to set the column's width manually as per the total space occupied by the cell text and the images. AutoSizeRow()/AutoSizeColumn() methods won't help here because they'd simply set the column/row width as per cell text, ignoring the space needed by images. Now that we have the images displayed in a cell, how does the user get to know if any of those images is clicked ? Moreover, how does he know specifically which image was clicked? Simple - we handle the BeforeMouseDown event of the grid, find the image rectangles and see if the mouse pointer is in any of those rectangles. Here's the code:

c1FlexGrid1.BeforeMouseDown += (s1, e1) =>  
 var hti = this.c1FlexGrid1.HitTest(new Point(e1.X, e1.Y));  

 if (hti.Row == 1 && hti.Column == 1)  
  var _row = hti.Row;  
  var _col = hti.Column;  

  if (this.c1FlexGrid1.GetDataDisplay(\_row, \_col).ToString() != null)  
   //cell rectangle  
   var \_cellRect = c1FlexGrid1.GetCellRect(\_row, _col);  
   //graphics object  
   var graphics = c1FlexGrid1.CreateGraphics();  
   //cell text  
   var \_text = c1FlexGrid1.GetDataDisplay(\_row, _col).ToString();  
   //text Font  
   var \_font = c1FlexGrid1.GetCellStyleDisplay(\_row, _col).Font;  
   //Text width  
   var text\_width = (int)graphics.MeasureString(\_text, _font).Width;  
   //Cursor location  
   var cursor_loc = new Point(e1.X, e1.Y);  

   //find x-coordinate for each image  
   var img1\_X = \_cellRect.Location.X + text_width - 10;  
   var img2\_X = img1\_X + img1.Width + 5;  
   var img3\_X = img2\_X + img2.Width + 5;  

   //find rectangle for each image  
   var img1\_Rect = new Rectangle(new Point(img1\_X, e1.Y), img1.Size);  
   var img2\_Rect = new Rectangle(new Point(img2\_X, e1.Y), img2.Size);  
   var img3\_Rect = new Rectangle(new Point(img3\_X, e1.Y), img3.Size);  

   //find which image-rectangle contains mouse-pointer  
   if (img1\_Rect.Contains(cursor\_loc))  
   c1FlexGrid1[\_row, \_col + 1] = "Left Image";  
   else if (img2\_Rect.Contains(cursor\_loc))  
   c1FlexGrid1[\_row, \_col + 1] = "Middle Image";  
   else if (img3\_Rect.Contains(cursor\_loc))  
   c1FlexGrid1[\_row, \_col + 1] = "Right Image";  

Since it's a demo, I've displayed the name of the image being clicked, in the adjacent cell of C1Flexgrid. Certainly, you may implement your own logic depending on the image. Here's a GIF that shows all three images being clicked and their positions getting updated in the adjacent cell. Download C# Sample Download VB.Net Sample


GrapeCity Developer Tools
comments powered by Disqus