C# How can I expand a cell in DataGridView to display multiline text and also an Image?

EDN Admin

Well-known member
Joined
Aug 7, 2010
Messages
12,794
Location
In the Machine
Hi all,
I couldnt make the title too clear of what Im trying to do so Ill get into explaining it a bit better.
All I want to do is create a DataGridView in Virtual Mode to hold 2 columns. First column is to contain the line number and the second is to contain a text and an image if required.
The text in the second column supports multiline, but only 2 lines allowed to be displayed in normal view. If the text has more than 2 lines, then an image to the right of the text should be displayed. When the user clicks on the image the cell should expand
to display all text lines. Next time the image is clicked again by the user the cell collapses and displays the first 2 lines again.
Any ideas of how to achieve this?
Here is an example code I made in my attempt to do what Im after.
Its a derived class of a DataGridViewColumn that contains a direved DataGridViewTextBoxCell.

Thank you in advance,
James


<pre lang="x-c# using System;
using System.Drawing;
using System.Globalization;
using System.Windows.Forms;
using System.ComponentModel;


namespace TestMySQL
{
// CUSTOM COLUMN
public class DataGridViewTextExpandColumn : DataGridViewColumn
{
public DataGridViewTextExpandColumn()
{
this.CellTemplate = new DataGridViewTextExpandCell();
this.ReadOnly = true;
}
}

// CUSTOM CELL
public class DataGridViewTextExpandCell : DataGridViewTextBoxCell
{
const int Img_Space = 4;
private readonly String[] EndLineSep = { "n", "r" };

private Image tImg;
private Bitmap tBmp;
private bool bMultiLine;
private bool bExpand;
private RectangleF imgLocation;

public DataGridViewTextExpandCell()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));

tBmp = new Bitmap(GetType(), "Mgnf.bmp");
tBmp.MakeTransparent(Color.Magenta);
tImg = new Bitmap(tBmp);

bMultiLine = false;
bExpand = false;
}

// MOUSE CLICK
protected override void OnMouseClick(DataGridViewCellMouseEventArgs e)
{
// CHECK IF MOUSE CLICK LOCATION IS WITHIN IMAGE
if (imgLocation != null && imgLocation.Contains(e.Location))
{
bExpand = !bExpand;
}

base.OnMouseClick(e);
}

// GET FORMATTED VALUE
protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, System.ComponentModel.TypeConverter valueTypeConverter, System.ComponentModel.TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context)
{
if (value != null)
{
String[] ss = ((String)value).Split(EndLineSep, StringSplitOptions.RemoveEmptyEntries);

bMultiLine = (ss.Length > 2);

if (ss.Length > 2 && !bExpand)
{
value = ss[0] + "n" + ss[1];
}
else
{
value = "";
for (int i = 0; i < ss.Length; i++)
{
if (i > 0)
value += "n";
value += ss;
}
}
}
return base.GetFormattedValue(value, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context);
}

// PAINT
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, "", "", errorText, cellStyle, advancedBorderStyle, paintParts);

// GET THE TEXT TO DISPLAY
String theText = (String)formattedValue;

// GET PARENT COLUMN
DataGridViewTextExpandColumn parent = (DataGridViewTextExpandColumn)this.OwningColumn;
// FORMAT TEXT
Font fnt = parent.InheritedStyle.Font;
SizeF msgSize = graphics.MeasureString(theText, fnt);

Color textColor = parent.InheritedStyle.ForeColor;
if ((cellState & DataGridViewElementStates.Selected) == DataGridViewElementStates.Selected)
{
textColor = parent.InheritedStyle.SelectionForeColor;
}

// DRAW THE TEXT
RectangleF strRec = new RectangleF(cellBounds.X, cellBounds.Y, (cellBounds.Width - tImg.Width - Img_Space), cellBounds.Height);
using (SolidBrush brush = new SolidBrush(textColor))
{
graphics.DrawString(theText, fnt, brush, strRec);
}

// DRAW THE IMAGE
if (bMultiLine)
{
int Xbound = cellBounds.Width - tImg.Width - Img_Space;
int Ybound = cellBounds.Y;
graphics.DrawImage(tImg, Xbound, Ybound);
// SET IMAGE LOCATION TO HANDLE MOUSE CLICK EVENT
//imgLocation = new RectangleF(Xbound, Ybound, tImg.Width, tImg.Height);
imgLocation = new RectangleF(Xbound, 1, tImg.Width, tImg.Height);
}
}// PAINT
}// CUSTOM CELL
}
[/code]


The problems I have with the code I posted are as follows:
1. The image location Im trying to set in the RectangleF imgLocation is not the real location of the image draw inside the cell. Hence Ive got it commented out and set it to something that works to test it, but still the real image is drawn after the text
and not where I want it.
2. The cell doesnt resize properly, even though the text has changed the cell keeps the original size. By manually having a button in my form to hide and then show the DataGridView Row that contains the multiple line text then it displays fine.


View the full article
 
Back
Top