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

想法是显示:

C:\ Program Files \ Microsoft Visual Studio 8 \ SDK \ v2.0 \ Bin \ 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"。如果我不对其进行硬编码(如下所示),则每次调整列的大小时都会进一步损坏。

以下是一对夫妇调整后的样子: 截图

这就是我目前正在做的事情。

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

这一直在变得越来越奇怪!!

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

以下是相关代码:

     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. 此行之后路径包含“&quot;。
  2. 此行之后Path包含与上面一样的字符串。
  3. 路径包含截断的文件路径(即“C:\ Documents and Setti ... \ Downloads”)
  4. 第二次调整大小:

    1. 在此行之后路径包含“&”;应该如此。
    2. 此行之后路径包含“C:\ Documents and Set ... \ Downloads \ 0 Documents \ Downloads”,这是我在删除无效字符之前的上一次迭代中的无效值(此处显示为'\ 0' )!!
    3. 现在路径是FUBAR,因为我开始使用一个搞砸的字符串而且它一直在变得更糟。
    4. 为什么在我明确为其分配值时,Path会被分配前一个函数调用中的无效值(在正确分配空字符串之后!)?!!!!!

有帮助吗?

解决方案

TextRenderer.MeasureText 方法是令人讨厌的一个 - 它改变了作为参数传递的实际字符串,因此它正在改变DataGridView引用的实际字符串。它实际上使.Net字符串可变

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

这会严重影响您应用的稳定性。如果你考虑到.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 复制用于垃圾收集)。

其他提示

您需要使用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; }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top