C# DataGridView: Long Text Truncated with “…” on the Left Side When the Column is Right-Aligned

后端 未结 3 583
北海茫月
北海茫月 2020-12-10 20:24

I have a question about the cell truncation (replaced with \"...\"):

How to display the replacement \"...\" on the left side of a cell when the column is right-align

3条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-12-10 21:26

    I've ended up implementing this by creating my own DataGridViewLeftCropTextBoxCell. Unfortunately DataGridViewTextBoxCell::Paint is bit a complicated method Reference Source .NET Framework 4.5.2 which uses many .NETs internal methods.

    But at first I let base class draw background and borders (and if there's no sensible foreground, just leave it).

    Then measure text and shrink it until it fits value bounds.

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

    And you can also create your own column type:

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

    I've borrowed text shrinking from steinar's answer and TextFormatFlags ComputeTextFormatFlagsForCellStyleAlignment from .NET Framework Reference Source.

提交回复
热议问题