Overview
Sometimes there is a need to enable a user to enter more than one line of text inside cell in datagridview table. This article explains how to wrap words inside datagridview cell and change row height while typing in text dynamically.
Important Notice: This solution is optimally functioning only when font typeface set for datagridview cell is Non Proportional, Fixed Width, or Mono-spaced. For proportional font typeface, there is a need to apply a different approach. Also proposed solution works only when word wrapping is allowed only in one column inside datagridview.
Article reference
Solution
Before the user starts typing text inside a cell we need to know if it is the column where word wrap is enabled, and if there is a need to set or change current auto size row property to NONE - DataGridViewAutoSizeRowsMode.None. Before user starts typing text inside cell, we need to know cell size, height, and width of cell, and how many characters can fit across cell width. So when user types more characters, then can fit in one cell row, cell height will be changed dynamically and words wrapped accordingly. Vice versa, if user deletes some characters from cell row and number of characters decreases, cell height shall be reduced. Also if user during typing text, manually changes cell width, all parameters must be recalculated.
For the first part of the solution, I have used datagridview beginedit event handler that is raised when user starts typing text in cell.
private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) {
if (e.ColumnIndex == 1) {
// Disable Data Grid View, Auto Size Rows
dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;
// Get Column width
int Column_Width = dataGridView1.Columns[e.ColumnIndex].Width;
// Calculate max number of characters that can fit across cell width
Max_Number_Of_Letters_In_A_Column = Calculate_Width_Of_Cell_In_Chars(Column_Width);
}
}
To calculate how many characters can fit across cell width, written the below next method.
int Calculate_Width_Of_Cell_In_Chars(int Cell_Width) {
// Calculate how many letters can fit across Cell Width
// for selected font type
int Number_Of_letters_In_Cell = 0;
string Word = "";
SizeF Measured_Length_Of_Word = new SizeF();
while (Measured_Length_Of_Word.Width <= Cell_Width) {
Number_Of_letters_In_Cell++;
Word += "W";
Measured_Length_Of_Word = G.MeasureString(Word, Data_Grid_View_Font, 0, StringFormat.GenericTypographic);
}
//
Number_Of_letters_In_Cell--;
return Number_Of_letters_In_Cell--;
}
Important Notice: dataGridView1 font, is transformed to Data Grid View Font used inside this method like this :
// Set New Font Type with size in Pixel and
// with measurement unit Pixel
Data_Grid_View_Font = new Font(dataGridView1.Font.FontFamily, dataGridView1.Font.SizeInPoints / (72 F / (float) DeviceDpi), dataGridView1.Font.Style, GraphicsUnit.Pixel, dataGridView1.Font.GdiCharSet);
Now here is the main method that implements ward wrap and cell height change :
void Wrap_Text_In_Cell() {
if (dataGridView1.IsCurrentCellInEditMode) {
if (dataGridView1.CurrentCell.ColumnIndex == 1) {
int Row_Height = dataGridView1.Rows[dataGridView1.CurrentCell.RowIndex].Height;
int Number_Of_Letters = dataGridView1.CurrentCell.EditedFormattedValue.ToString().Length;
if (Number_Of_Letters > Min_Number_Of_Letters_In_A_Column && Number_Of_Letters % Max_Number_Of_Letters_In_A_Column == 0) {
int New_Row_Height = Initial_Data_Grid_View_Row_Height + (Number_Of_Letters / Max_Number_Of_Letters_In_A_Column) * Font_Height;
if (New_Row_Height > Row_Height) dataGridView1.Rows[dataGridView1.CurrentCell.RowIndex].Height = New_Row_Height;
else {
New_Row_Height = Initial_Data_Grid_View_Row_Height + (Number_Of_Letters / Max_Number_Of_Letters_In_A_Column - 1) * Font_Height;
dataGridView1.Rows[dataGridView1.CurrentCell.RowIndex].Height = New_Row_Height;
}
}
}
}
}
It is a simple calculation implemented to find out the height of cell in relation to the number of entered characters.
This method is called every time user press and release key, while typing in text, and for that event used this method :
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
Wrap_Text_In_Cell();
return base.ProcessCmdKey(ref msg, keyData);
}
To find out if user has changed cell width manually, and recalculate initial parameters I have used this event handler :
private void dataGridView1_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e) {
// Recalculate max number of letters
// Set column width
if (dataGridView1.CurrentCell != null) {
int Column_Width = dataGridView1.Columns[e.Column.Index].Width;
Max_Number_Of_Letters_In_A_Column = Calculate_Width_Of_Cell_In_Chars(Column_Width);
if (Max_Number_Of_Letters_In_A_Column > 0) Wrap_Text_In_Cell();
}
}
And finally, when user finishes editing text in cell and hits enter, it is necessary to restore data grid view rows auto size mode :
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) {
// Enable Data Grid View, Auto Size Rows
dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCells;
}
At the top of this article, there is a download link of full solution written in VS 2022, .Net framework 4.8, download it and thoroughly explore code.
All the best,