我对单元格截断有疑问(替换为“...”):
当列右对齐时,如何在单元格的左侧显示替换“...”?
我使用的是非等宽字体,所以我不能只计算字符来做一些字符串操作作为解决方法,我需要一个解决方案。我相信应该有。
为了说明我的问题,我在这里模拟我的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
答案 0 :(得分: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);
}
}
}
答案 1 :(得分:2)
我最终通过创建自己的DataGridViewLeftCropTextBoxCell
来实现这一点。不幸的是DataGridViewTextBoxCell::Paint
是bit 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 answer的.NET Framework Reference Source和TextFormatFlags ComputeTextFormatFlagsForCellStyleAlignment
的文字。
答案 2 :(得分: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
枚举的哪个标志。