Discussion:
DataGridView text wrapping
(too old to reply)
mikebk
2009-06-30 17:14:01 UTC
Permalink
I have some text that's too wide to fit into a DatagridView column so I have
used CellStyle.WrapMode = System.Windows.Forms.DataGridViewTriState.True.
Unfortunately, it only wraps on blanks, no matter how long the string is.
This means that I can't see last part of the string.

How can I have the DataGridView display a long string wrapped at the column
width?

Thanks

Mike
John Bundy
2009-07-06 13:46:02 UTC
Permalink
I can't find where you made that selection, but try this. On the properties
menu select Columns and click on Collections to open Edit Columns screen. On
the left click on the column you want to wrap. Then select DefaultCellStyle
and change WrapMode to True. See if that works for you, i worked well in the
example i tried.
--
-John
Please rate when your question is answered to help us and others know what
is helpful.
Post by mikebk
I have some text that's too wide to fit into a DatagridView column so I have
used CellStyle.WrapMode = System.Windows.Forms.DataGridViewTriState.True.
Unfortunately, it only wraps on blanks, no matter how long the string is.
This means that I can't see last part of the string.
How can I have the DataGridView display a long string wrapped at the column
width?
Thanks
Mike
mikebk
2009-07-06 16:14:01 UTC
Permalink
Post by John Bundy
I can't find where you made that selection, but try this. On the properties
menu select Columns and click on Collections to open Edit Columns screen. On
the left click on the column you want to wrap. Then select DefaultCellStyle
and change WrapMode to True. See if that works for you, i worked well in the
example i tried.
Thanks for your reply. I tried using the designer to set wrapmode instead of
using code but it didn't affect the problem.

I did write a small test program that demonstrates the problem. I used the
designer to create a two column DataGridView then added a button. I then
inserted code into the button's click event to put some text illustrating the
program. The text string has no embedded blanks.

When I run the program and click the button, the text is shown extending
past the end of the column even though wrapping is enabled.

Here's the test code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace TestDgvWrap
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
testDgv.Columns[1].Width = 700;
string longishString =
"XXXX/XXXXXXXXX,XXX-XXX-XXXX/XXXXXXXXX,XXX-XXX-XXXX/XXXXXXXXX_XXXX,XX/XXXXXXXXX_XXXXXX,XX/XXXXXXXX,XX/XXXXXX_XXXXXXX,XXXX.XX/XXXXXX_XXXX_XXX,XX.XX/XXXXXX_XXXXXXXXX,X.XX/XXXXXX_XXX,XXX.XX/XXXXXXX_";

testDgv.AutoResizeRows(DataGridViewAutoSizeRowsMode.AllCellsExceptHeaders);
testDgv.AutoSizeColumnsMode =
DataGridViewAutoSizeColumnsMode.None;
testDgv.Columns[1].AutoSizeMode =
DataGridViewAutoSizeColumnMode.None;
testDgv.DefaultCellStyle.WrapMode =
System.Windows.Forms.DataGridViewTriState.True;
testDgv.RowTemplate.DefaultCellStyle.WrapMode =
System.Windows.Forms.DataGridViewTriState.True;
testDgv.AllowUserToResizeRows = true;
testDgv.Rows.Add(2);
testDgv.Rows[1].Cells[1].Value = longishString;
}
}
}

Mike
Linda Liu[MSFT]
2009-07-07 04:07:44 UTC
Permalink
Hi Mike,

I performed a test on your sample code and did see the problem. My
suggestion is to paint the cell value in the DataGridViewTextBoxCell by
yourself. To do this, handle the CellPaint event of the DataGridView. For
example:

void dataGridView1_CellPainting(object sender,
DataGridViewCellPaintingEventArgs e)
{
if (e.ColumnIndex == 0)
{
e.PaintBackground(e.ClipBounds, true);
using (SolidBrush sb = new
SolidBrush(e.CellStyle.ForeColor))
{
e.Graphics.DrawString(e.FormattedValue.ToString(),
e.CellStyle.Font, sb, e.CellBounds);
}
e.Handled = true;
}
}

To reuse the above code, a way is to create a new type
DataGridViewTextBoxCell which paints its cell value with wrapping. To do
this, we need to create a custom column that contains the new type cell.
The following is a sample:

public class MyTextBoxColumn : DataGridViewColumn
{
public MyTextBoxColumn()
: base(new MyTextBoxCell())
{
}
public override DataGridViewCell CellTemplate
{
get
{
return base.CellTemplate;
}
set
{
if (value != null &&
!value.GetType().IsAssignableFrom(typeof(MyTextBoxCell)))
{
throw new InvalidCastException("Must be a
MyTextBoxCell");
}
base.CellTemplate = value;
}
}
}
public class MyTextBoxCell : DataGridViewTextBoxCell
{
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, value, formattedValue, errorText, cellStyle,
advancedBorderStyle, paintParts);
using (SolidBrush backcolorBrush = new
SolidBrush(cellStyle.BackColor))
{
graphics.FillRectangle(backcolorBrush, new
Rectangle(cellBounds.X + 1, cellBounds.Y + 1, cellBounds.Width - 2,
cellBounds.Height - 2));

}
using (SolidBrush highlightBrush = new
SolidBrush(SystemColors.Highlight))
if ((cellState & DataGridViewElementStates.Selected) ==
DataGridViewElementStates.Selected)
{
graphics.FillRectangle(highlightBrush, new
Rectangle(cellBounds.X + 1, cellBounds.Y + 1, cellBounds.Width - 2,
cellBounds.Height - 2));
}
using (SolidBrush forecolorBrush = new
SolidBrush(cellStyle.ForeColor))
{
graphics.DrawString(formattedValue.ToString(),
cellStyle.Font, forecolorBrush, cellBounds);
}
}
}

Add the instances of the MyTextBoxColumn class into your DataGridView
instead of the standard DataGridViewTextBoxColumn.

Hope this helps.
If you have any question, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
***@microsoft.com.

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
mikebk
2009-07-08 21:14:01 UTC
Permalink
Post by Linda Liu[MSFT]
Hi Mike,
I performed a test on your sample code and did see the problem. My
suggestion is to paint the cell value in the DataGridViewTextBoxCell by
yourself.
That's a big step forward! The problem I've noticed is that DrawString seems
remove a bit of space between lines compared to what the dgv draws normally.
If I click on the cell, and the Editing control is showing, the spacing is
normal and fills the cell. If I don't use the CellPainting event, the cell is
also filled (This test text has line ends so it doesn't actually get
wrapped). Using the the CellPainting event, the text fills only 80-90 % of
the cell. Also, if I use MeasureText to find the height of the string, the
height calculated matches the cell height, confirming that the normal
painting and editing control are using the correct spacing while DrawString
isn't.

Is there somewhere that the spacing between lines can be customized?

Thanks

Mike
Linda Liu[MSFT]
2009-07-09 03:25:33 UTC
Permalink
Hi Mike,

Thank you for your reply!
The problem I've noticed is that DrawString seems remove a bit of space
between lines compared to what the dgv draws normally.

I don't see the space between lines varies when drawing with the DrawString
method. Could you please show me a screen shot about this problem? You can
send the screen shot to my mail box v-***@microsoft.com.

Sincerely,
Linda Liu
Microsoft Online Community Support
Linda Liu[MSFT]
2009-07-10 08:34:55 UTC
Permalink
Hi Mike,

Thank you for your screen shot and sample code.

To me, it's not the space between lines that varies when calling the
Graphics.DrawString method, but it's the padding between the cell bound and
the cell value that varies. The text painted by the Graphics.DrawString
method doesn't have a padding to the cell bound.

To solve this problem, adjust the rectangle passed to the
Graphics.DrawString method.

As for measuring text, both the TextRender.MeasureText method and the
DataGridViewCell.MeasureTextHeight method measure the size of a given text
in a single line. On the contrary, the Graphics.MeasureString method
measure the size of a given text using a bound rectangle.

I modify your sample code as follows:

void testDgv_CellPainting(object sender, DataGridViewCellPaintingEventArgs
e)
{
if ((e.RowIndex == 1) && (e.ColumnIndex > 0) &&
(e.FormattedValue != null))
{
// you needn¡¯t create a graphics object here. Use the
e.Graphics object directly.
//Graphics graphics = testDgv.CreateGraphics();

SizeF sizeGraph =
e.Graphics.MeasureString(e.FormattedValue.ToString(), e.CellStyle.Font, new
SizeF(Convert.ToSingle(e.CellBounds.Width),
Convert.ToSingle(e.CellBounds.Height)));

RectangleF cellBounds = e.CellBounds;
cellBounds.Height = cellBounds.Height - 5;
// ajust the rectangle used to draw the cell value here
if (e.CellBounds.Height > sizeGraph.Height)
{
cellBounds.Y += (e.CellBounds.Height - sizeGraph.Height) / 2;
}
else
{
cellBounds.Y += 2;
}

e.PaintBackground(e.ClipBounds, true);
using (SolidBrush sb = new SolidBrush(e.CellStyle.ForeColor))
{
e.Graphics.DrawString(e.FormattedValue.ToString(),
e.CellStyle.Font, sb, cellBounds);
}
e.Handled = true;
}
}

Hope this helps.
If you have any question, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support
mikebk
2009-07-10 14:36:01 UTC
Permalink
Post by Linda Liu[MSFT]
To me, it's not the space between lines that varies when calling the
Graphics.DrawString method, but it's the padding between the cell bound and
the cell value that varies. The text painted by the Graphics.DrawString
method doesn't have a padding to the cell bound.
To solve this problem, adjust the rectangle passed to the
Graphics.DrawString method.
The "padding" you observed is is really a result of the dgv having alignment
set to DataGridViewContentAlignment.MiddleLeft. As a result it can be fixed
by using "testDgv.DefaultCellStyle.Alignment =
DataGridViewContentAlignment.TopLeft;" in the button's click handler.

That's isn't the problem that I was asking about. Instead, the problem is
that the lines drawn with the paint handler are closer together than the ones
drawn by either the dgv's DataGridViewTextBoxCell or the
DataGridViewTextBoxEditingControl used once you've selected text in the cell.

The difference is small but it leaves considerable blank space between the
cell border and the bottom text line. I used PixelRuler to measure the sizes.
13 lines drawn by DataGridViewTextBoxCell or the
DataGridViewTextBoxEditingControl take 166 pixels. The same 13 lines drawn
by the paint event take 160 pixels.

Does this give you any ideas?

Thanks

Mike
Linda Liu[MSFT]
2009-07-14 06:56:57 UTC
Permalink
Hi Mike,

Thank you for your reply and detailed explanation!

I use Reflector to look into the way that a DataGridViewTextBoxCell uses to
paint its cell value and find that it calls the TextRenderer.DrawText
method to draw strings.

So it seems that there's a tiny difference for the texts drawn by the
TextRenderer.DrawText method and the Graphics.DrawString method.

Unfortunately, we can't use the TextRenderer.DrawText method to draw cell
value in a DataGridViewTextBoxCell because even if we pass the
TextFormatFlags.WordBreak flag to this method, the a long string won't be
drawn to multiple lines if there's no blank in this long string. This is
the problem you mentioned in your previous message.

We have to use the Graphics.DrawString method to draw the cell value in a
DataGridViewTextBox to ensure a long string can be painted to multiple
lines.

Sincerely,
Linda Liu
Microsoft Online Community Support
mikebk
2009-07-14 13:59:02 UTC
Permalink
Post by Linda Liu[MSFT]
Unfortunately, we can't use the TextRenderer.DrawText method to draw cell
value in a DataGridViewTextBoxCell because even if we pass the
TextFormatFlags.WordBreak flag to this method, the a long string won't be
drawn to multiple lines if there's no blank in this long string. This is
the problem you mentioned in your previous message.
I had noticed the difference between TextFormatFlags and StringFormatFlags
that produces the wrapping difference. I'm a bit surprised that the situation
hasn't been remedied as it's been there since at least .NET Framework 2.

Does Microsoft ever correct "architectural oversights" like this or the
inability to easily scroll a dgv so a specific row is visible but not
necessarily at the top of the visible region?

Thanks for your help anyway.

Mike
Linda Liu[MSFT]
2009-07-16 09:21:23 UTC
Permalink
Hi Mike,

Thank you for your prompt reply!
Post by mikebk
Does Microsoft ever correct "architectural oversights" like this or the
inability to easily scroll a dgv so a specific row is visible but not
necessarily at the top of the visible region?

Could you please tell me what you mean in the above sentence?

Sincerely,
Linda Liu
Microsoft Online Community Support
mikebk
2009-07-16 16:41:01 UTC
Permalink
Having functionality to wrap text at other than at white space sounds like
really basic functionality. It's basic enough that the Editing control (and
of course the DrawString function) include it. I imagine that most
applications that wrap text wrap when a character exceeds the avaiable width.
At this point, there's no way to tell a dgv to wrap at the end of a line so
it would require some kind of a change to the api. For instance, TextFormat
flags might take a WrapAtWidth flag. This sounds like a simple change but the
api hasn't changed since .Net 2.0.

Likewise, scrolling a dgv so that a specific row is visible is only directly
supported if you want the row positioned at the top of the scrolling region.
I was wanting to position a row that was added at the bottom of scrolling
region and found that I had to iterate through the rows calculating each
row's height to set the FirstVisibleScrollingRowIndex appropriately.

Anyway, these seemed to be the sort of thing that happens when a new set of
classes is introduced and would be remedied in the "next release".

Thanks again.

Mike
Post by Linda Liu[MSFT]
Hi Mike,
Thank you for your prompt reply!
Post by mikebk
Does Microsoft ever correct "architectural oversights" like this or the
inability to easily scroll a dgv so a specific row is visible but not
necessarily at the top of the visible region?
Could you please tell me what you mean in the above sentence?
Sincerely,
Linda Liu
Microsoft Online Community Support
Linda Liu[MSFT]
2009-07-17 08:00:17 UTC
Permalink
Hi Mike,

Thank you for your expanation! I understand your concern.

We're always willing to hear customers' voice. Customer feedback is a
critical part of a successful, impactful product release.

Unfortunately, another part is the reality of schedules and the need to get
all the bits into production. The evaluation is carefully done and
considered many aspects including fix cost, breaking changes,
globalization, performance, etc.

We do our best to meet our customers' requirements as far as possible.

Well, I consider I can close this issue if you don't have any question.

Sincerely,
Linda Liu
Microsoft Online Community Support

Loading...