2010-10-10 53 views
4

我有一个关于小区的截断问题(改为“...”):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... 

我想我已经说清楚了。

谢谢。请帮助我。

彼得

P.S:同样的问题可以在此链接中找到: http://objectmix.com/csharp/341736-datagridview-cell-format-question.html

回答

2

这绝对是做了一个不寻常的事情 - 但(像其他东西)是可以做到的。这是测量字符串大小并将其与单元格大小进行比较的问题。 (请注意,我假设数据是由用户输入如果你正在数据绑定,你基本上都需要消耗其他事件。)

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

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); 
     } 
    } 
} 
+0

嗨steinar,你可能是一个解决方案,虽然它是不合适的。我在DataBinding中使用它(不是用于编辑),并且我把你的代码放在了我的CellPainting事件中,它有点慢。 – 2010-10-11 06:41:51

+0

请参阅我自己的答案。谢谢。 – 2010-10-11 06:47:50

+0

是的,覆盖单元格绘画的解决方案总是更加高效,在处理相当数量的行时是必要的。 – steinar 2010-10-12 00:08:45

1

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

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打开。

2

我最终通过创建我自己的DataGridViewLeftCropTextBoxCell来实现这一点。不幸的是DataGridViewTextBoxCell::Paintbit 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 answerTextFormatFlags ComputeTextFormatFlagsForCellStyleAlignment萎缩.NET Framework Reference Source