我最终通过创建我自己的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。
嗨steinar,你可能是一个解决方案,虽然它是不合适的。我在DataBinding中使用它(不是用于编辑),并且我把你的代码放在了我的CellPainting事件中,它有点慢。 – 2010-10-11 06:41:51
请参阅我自己的答案。谢谢。 – 2010-10-11 06:47:50
是的,覆盖单元格绘画的解决方案总是更加高效,在处理相当数量的行时是必要的。 – steinar 2010-10-12 00:08:45