格式化DataGridView单元格而不更改基础值?

问题描述:

我有一个未绑定的DataGridView(在VS 2008中),其中一列包含文件路径。我想在ColumnWidthChanged事件中使用TextRenderer类来格式化字符串,而不实际修改基础值。问题是表格的内容在表格关闭时保存,我不想保存格式化的值。我想我只是太深,看不到明显的解决方案,所以我要依靠你们指出:-)。格式化DataGridView单元格而不更改基础值?

这样做是为了显示此:

C:\ Program Files文件\微软的Visual Studio 8 \ SDK \ 2.0 \斌\的Gacutil.exe

...因为这(视列的宽度):

C:\ Program Files文件\ Microso位... \将Gacutil.exe


看来我说话太快了。我从TextRenderer.MeasureText()中得到了一些非常奇怪的结果。如果我将路径值硬编码为“C:\ Documents and Settings \ jluce \ My Documents \ Downloads”,它将以 C:\ Documents and Settings \ jluce \ M ... \ Downloads \ 0wnloads结尾。 “T硬编码(如下面)它获取每个I调整列时进一步破坏

这里是什么样子后,一对夫妇的调整大小:。 Screenshot

这里是目前我在做什么

if (e.ColumnIndex == 1) 
    { 
    foreach (DataGridViewRow Row in mappingsDataGrid.Rows) 
    { 
     string Path = (string)Row.Cells[1].Value; 
     Path = Path.Trim(); 

     TextRenderer.MeasureText(Path, e.CellStyle.Font, 
     new Size(mappingsDataGrid.Columns[e.ColumnIndex].Width, Row.Height), 
      TextFormatFlags.ModifyString | TextFormatFlags.PathEllipsis); 

     e.Value = Path; 
    } 
    } 

This jus不断变得怪异!

我设法通过迭代每个字符并删除坏字符来修复mangled字符串的问题。但是,现在我有一个更疯狂的问题。我在事件处理程序中分配的局部变量在调用之间保留其值。

下面是相关代码:

 string Path = ""; // <-- #1 
    Path = "C:\\Documents and Settings\\jluce\\My Documents\\Downloads"; // <-- #2 

     TextRenderer.MeasureText(Path, Row.Cells[1].Style.Font, 
     new Size((mappingsDataGrid.Columns[e.Column.Index].Width), Row.Height), 
      TextFormatFlags.ModifyString | TextFormatFlags.PathEllipsis); 

     // Left out code that strips invalid chars 

     Row.Cells[1].Value = Path; // <-- #3 
     Path = null; 

第一次调整柱(参见#的上述评论):

  1. 后此行路径中包含 “”。
  2. 在此行之后Path包含字符串,就像它出现在上面一样。
  3. Path包含截断的文件路径,因为它应该(即 “C:\ Documents和Setti ... \下载”)

第二次调整:

  1. 后此行路径中包含 “” , 正如它应该。
  2. 在此行路径中包含“C:\ Documents and Settings ... \ Downloads \ 0 Documents \ Downloads”,这是前面迭代的无效值,我将无效字符(在此处显示为'\ 0 “)!
  3. 现在路径是FUBAR,因为我从一根拧起来的绳子开始,它变得越来越糟。

当我明确地为它指定一个值时,为什么Path会被分配上一个函数调用的无效值(在正确指定空字符串后!)!!!!!

+0

看到我的“答案”下面的问题更具体的细节... – jluce50 2009-10-23 15:39:48

TextRenderer.MeasureText方法是nasty one - 它改变了传递的实际字符串作为参数,所以它改变了DataGridView引用的实际字符串。它实际上使.Net字符串可变

似乎这种荒谬的方法并没有改变字符串的实际Length,而只是用\0来覆盖其中一个字符来指示字符串的结尾(如普通C中的以空字符结尾的字符串)。这是一些有趣的东西!

这可能会严重影响应用程序的稳定性。如果考虑到.Net使用string interning,你可能会开始得到各种奇怪的结果,因为你注意到你的字符串常量看起来不再是常量。

第一步是创建字符串的副本(与相同字符的新实例):

string Path = String.Copy(e.Value as string ?? ""); 

,而不是

string Path = (string)Row.Cells[1].Value; 

这将确保无论什么TextRenderer呢,原来字符串将保持不变。

之后,您需要摆脱修改过的字符串中的空字符。

通过这样做:

if (Path.IndexOf('\0') >= 0) 
    e.Value = Path.Substring(0, Path.IndexOf('\0')); 
else 
    e.Value = Path; 

您将创建一个干净的,修改后的字符串的一个新实例(离开我们的临时Path副本未引用的垃圾收集)。

+0

会这样做,但是仍然存在MeasureText会破坏数据的问题。即使我使用硬编码字符串替换您所指的行,也会发生这种情况。 – jluce50 2009-10-23 16:04:43

+0

谢谢,这似乎工作!我同意,这种方法是一个奇怪的。很少的文档和非常不可预知的结果。 – jluce50 2009-10-24 14:22:04

在打印之前,您需要使用CellFormatting事件来更改给定值(原始对象值不会被修改)。在你的情况,你可以检查它是否是一个正确的列通过验证e.ColumnIndex变量和更改e.Value文本和我一样如下:

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     dataGridView1.DataSource = new List<Person>(new Person[] { new Person() { Name = "André", Adress = "Brazil" } }); 
    } 

    private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) 
    { 
     e.Value = e.Value + " modified"; 
    } 
} 

class Person 
{ 
    public String Name { get; set; } 
    public String Adress { get; set; } 
} 
+0

我有一种感觉,这是一件简单的事情。谢谢!! – jluce50 2009-10-23 13:13:38