I have a question about the cell truncation (replaced with \"...\"):
How to display the replacement \"...\" on the left side of a cell when the column is right-align
I've ended up implementing this by creating my own DataGridViewLeftCropTextBoxCell. Unfortunately DataGridViewTextBoxCell::Paint is bit a complicated method Reference Source .NET Framework 4.5.2 which uses many .NETs internal methods.
But at first I let base class draw background and borders (and if there's no sensible foreground, just leave it).
Then measure text and shrink it until it fits value bounds.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace Project
{
public class DataGridViewLeftCropTextBoxCell : DataGridViewTextBoxCell
{
///
/// Paints contents
///
///
///
///
///
///
///
///
///
///
///
///
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 )
{
string formattedString = formattedValue as string;
// Nothing to draw
if (String.IsNullOrEmpty( formattedString )) {
base.Paint( graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts );
return;
}
// Draw parently without foreground
base.Paint( graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts & ~DataGridViewPaintParts.ContentForeground );
// No foreground?
if ((paintParts & DataGridViewPaintParts.ContentForeground) == DataGridViewPaintParts.None) {
return;
}
// Calculate value bounds
Rectangle borderWidths = BorderWidths( advancedBorderStyle );
Rectangle valBounds = cellBounds;
valBounds.Offset( borderWidths.X, borderWidths.Y );
valBounds.Width -= borderWidths.Right;
valBounds.Height -= borderWidths.Bottom;
bool cellSelected = (cellState & DataGridViewElementStates.Selected) != 0;
// Prepare text flags
TextFormatFlags flags = ComputeTextFormatFlagsForCellStyleAlignment( this.DataGridView.RightToLeft == RightToLeft.Yes, cellStyle.Alignment, cellStyle.WrapMode );
if ((flags & TextFormatFlags.SingleLine) != 0) {
flags |= TextFormatFlags.EndEllipsis;
}
// Prepare size of text
Size s = TextRenderer.MeasureText( graphics,
formattedString,
cellStyle.Font
);
// Text fits into bounds, just append
if (s.Width < valBounds.Width) {
TextRenderer.DrawText( graphics,
formattedString,
cellStyle.Font,
valBounds,
cellSelected ? cellStyle.SelectionForeColor : cellStyle.ForeColor,
flags );
return;
}
// Prepare
StringBuilder truncated = new StringBuilder( formattedString );
truncated.Insert( 0, "..." );
// Truncate the string until it's small enough
while ((s.Width > valBounds.Width) && (truncated.Length > 5)) {
truncated.Remove( 3, 1 );
formattedString = truncated.ToString();
s = TextRenderer.MeasureText( graphics,
formattedString,
cellStyle.Font
);
}
TextRenderer.DrawText( graphics,
formattedString,
cellStyle.Font,
valBounds,
cellSelected ? cellStyle.SelectionForeColor : cellStyle.ForeColor,
flags
);
}
}
}
And you can also create your own column type:
class DataGridViewLeftCropTextBoxColumn : DataGridViewTextBoxColumn
{
public override DataGridViewCell CellTemplate
{
get { return new DataGridViewLeftCropTextBoxCell(); }
set { base.CellTemplate = value; }
}
}
I've borrowed text shrinking from steinar's answer and TextFormatFlags ComputeTextFormatFlagsForCellStyleAlignment from .NET Framework Reference Source.