C # DataGridView: длинный текст усекается с «...» на левой стороне, когда столбец выравнивается по правому краю - PullRequest
4 голосов
/ 11 октября 2010

У меня вопрос по поводу усечения ячейки (заменено на "..."):

Как отобразить замену "..." в левой части ячейки, если столбец выровнен по правому краю?

Я использую шрифт не равной ширины, поэтому я не могу просто посчитать символы, чтобы выполнить некоторые манипуляции со строками в качестве обходного пути, мне нужно решение. Я считаю, что должно быть.

Чтобы проиллюстрировать мой вопрос, я моделирую свой 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...

Думаю, я ясно дал понять.

Спасибо. Пожалуйста, помогите мне.

Peter

P.S .: тот же вопрос можно найти по этой ссылке: http://objectmix.com/csharp/341736-datagridview-cell-format-question.html

Ответы [ 3 ]

2 голосов
/ 08 апреля 2015

В итоге я реализовал это, создав собственный 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
    {

        /// <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; }
    }
}
<Ч />

Я заимствовал сокращенный текст из ответа Стейнара и TextFormatFlags ComputeTextFormatFlagsForCellStyleAlignment из .NET Framework Reference Source .

2 голосов
/ 11 октября 2010

Это определенно необычная вещь, но (как и все остальное) это можно сделать.Это вопрос измерения размера строки и сравнения ее с размером ячейки.(Обратите внимание, что я предполагаю, что данные вводятся пользователем. Если вы привязываете данные, вам в основном приходится использовать другие события.)

Это работает, но может потребоваться некоторая подстройка:

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);
        }
    }
}
1 голос
/ 11 октября 2010

Я сделал обходной путь, он работает, кроме «...» (усечение работает хорошо)

    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 включить.

...