我最终通过创建自己的DataGridViewLeftCropTextBoxCell 来实现这一点。不幸的是,DataGridViewTextBoxCell::Paint 是 bit a complicated method Reference Source .NET Framework 4.5.2,它使用了许多 .NET 内部方法。
但一开始我让基类绘制背景和边框(如果没有合理的前景,就离开它)。
然后测量文本并缩小它,直到它适合值范围。
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
{
/// <summary>
/// Paints contents
/// </summary>
/// <param name="graphics"></param>
/// <param name="clipBounds"></param>
/// <param name="cellBounds"></param>
/// <param name="rowIndex"></param>
/// <param name="cellState"></param>
/// <param name="value"></param>
/// <param name="formattedValue"></param>
/// <param name="errorText"></param>
/// <param name="cellStyle"></param>
/// <param name="advancedBorderStyle"></param>
/// <param name="paintParts"></param>
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
);
}
}
}
您还可以创建自己的列类型:
class DataGridViewLeftCropTextBoxColumn : DataGridViewTextBoxColumn
{
public override DataGridViewCell CellTemplate
{
get { return new DataGridViewLeftCropTextBoxCell(); }
set { base.CellTemplate = value; }
}
}
我从steinar's answer 和TextFormatFlags ComputeTextFormatFlagsForCellStyleAlignment 借用了缩小的文字,从.NET Framework Reference Source。