【问题标题】:C# DataGridView: Long Text Truncated with "..." on the Left Side When the Column is Right-AlignedC# DataGridView:当列右对齐时,长文本在左侧被“...”截断
【发布时间】:2010-10-10 21:43:10
【问题描述】:

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

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

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

为了说明我的问题,我在这里模拟我的 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

【问题讨论】:

    标签: c# datagridview truncate


    【解决方案1】:

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

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

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

    【讨论】:

    • 嗨 steinar,你的可能是一个解决方案,尽管它效率低下。我在 DataBinding 中使用它(不是为了编辑),我把你的代码放在我的 CellPainting 事件中,它有点慢。
    • 在下面查看我自己的答案。谢谢。
    • 是的,覆盖单元格绘制的解决方案总是效率更高,在处理大量行时是必要的。
    【解决方案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

    【讨论】:

      【解决方案3】:

      我已经做了一个解决方法,除了“...”(截断效果很好)之外它都可以工作

          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 枚举的哪个标志。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-02-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-22
        • 2016-07-11
        • 2020-07-23
        相关资源
        最近更新 更多