C#DataGridView:当列是右对齐时,长文本在左侧以“…”截断

我有一个关于单元格截断的问题(替换为“…”):

当列右对齐时,如何在单元格的左侧显示替换“…”?

我使用非等宽字体,所以我不能只计算字符来做一些字符串操作作为解决方法,我需要一个解决方案。 我相信应该有。

为了说明我的问题,我在这里模拟我的DataGridView

Left Context (Right aligned column) | Center Word | Right Context (Left aligned column) left context not truncated | CenterWord | Right context not truncated ...Here is the long left context truncated | CenterWord | Here is the long right context truncated... 

我想我已经说清楚了。

谢谢。 请帮帮我。

彼得

PS:同样的问题可以在这个链接找到: http : //objectmix.com/csharp/341736-datagridview-cell-format-question.html

这绝对是一件不寻常的事情 – 但是(就像其他事情一样)它可以做到。 这是一个测量字符串大小并将其与单元格大小进行比较的问题。 (请注意,我假设数据是由用户输入的。如果您是数据绑定,则基本上必须使用其他事件。)

这可行,但可能需要一些微调:

 public partial class Form1 : Form { public Form1() { InitializeComponent(); dataGridView1.Columns.Add("col1", "col1"); dataGridView1.Columns[0].CellTemplate.Style.Alignment = DataGridViewContentAlignment.MiddleRight; dataGridView1.Columns.Add("col2", "col2"); dataGridView1.Columns.Add("col3", "col3"); dataGridView1.Rows.Add(); dataGridView1.CellEndEdit += new DataGridViewCellEventHandler(dataGridView1_CellEndEdit); dataGridView1.ColumnWidthChanged += new DataGridViewColumnEventHandler(dataGridView1_ColumnWidthChanged); } void dataGridView1_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e) { if (e.Column.Index == 0) { // We need to truncate everything again when the width changes foreach (DataGridViewRow row in dataGridView1.Rows) { RightTruncateText(row.Cells[0]); } } } void RightTruncateText(DataGridViewCell cell) { // check if the content is too long: using (Graphics g = Graphics.FromHwnd(this.Handle)) { SizeF size = g.MeasureString((string)cell.Tag, dataGridView1.Font); // NOTE: using the tag if (size.Width > cell.Size.Width) { StringBuilder truncated = new StringBuilder((string)cell.Tag); truncated.Insert(0, "..."); // Truncate the string until small enough (NOTE: not optimized in any way!) while (size.Width > cell.Size.Width) { truncated.Remove(3, 1); size = g.MeasureString(truncated.ToString(), dataGridView1.Font); } cell.Value = truncated.ToString(); } else { cell.Value = cell.Tag; } } } void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) { if (e.ColumnIndex == 0) { // Save the value in the tag but show the truncated value DataGridViewCell cell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex]; cell.Tag = cell.Value; // Saving the actual state RightTruncateText(cell); } } } 

我最终通过创建自己的DataGridViewLeftCropTextBoxCell来实现这一点。 不幸的是DataGridViewTextBoxCell::Paint是一个复杂的方法参考源.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 { ///  /// 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 ); } } } 

您还可以创建自己的列类型:

 class DataGridViewLeftCropTextBoxColumn : DataGridViewTextBoxColumn { public override DataGridViewCell CellTemplate { get { return new DataGridViewLeftCropTextBoxCell(); } set { base.CellTemplate = value; } } } 

我借用了来自.NET Framework Reference Source的 steinar的答案和TextFormatFlags ComputeTextFormatFlagsForCellStyleAlignment文字。

我做了一个解决方法,它的工作除了“…”(截断效果很好)

  protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e) { base.OnCellPainting(e); if (e.RowIndex >= 0 && e.ColumnIndex >= 0 && CustomRightToLeftColumnNames.Contains(this.Columns[e.ColumnIndex].Name)) { // Method 2: e.PaintBackground(e.CellBounds, true); if (e.FormattedValue != null) { TextFormatFlags flags = TextFormatFlags.RightToLeft | TextFormatFlags.VerticalCenter | TextFormatFlags.Right | TextFormatFlags.LeftAndRightPadding;// | //TextFormatFlags.EndEllipsis; TextRenderer.DrawText ( e.Graphics, e.FormattedValue.ToString(), e.CellStyle.Font, e.CellBounds, e.CellStyle.ForeColor, flags ); } e.Handled = true; } } 

这个解决方案的唯一问题是我不知道如何设置TextFormatFlags以获得我想要的正确行为,与DataGridView.RightToLeft = Yes时完全相同。

如果我打开TextFormatFlags.EndEllipsis ,三个点“…”将出现在左侧,但它会从字符串的右端截断。

我不确定要打开哪个TextFormatFlags枚举标志。