我有一个未绑定的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“。如果我不对其进行硬编码(如下所示),每次调整列的大小时都会进一步损坏。
以下是一对夫妇调整后的样子: 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;
}
}
这一直在变得越来越奇怪!!
我设法通过迭代每个字符并删除坏字符来解决受损字符串的问题。但是,现在我有一个更疯狂的问题。我在事件处理程序中分配的局部变量在调用之间保留其值。
以下是相关代码:
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;
第一次调整大小列(请参阅上面评论中的#):
第二次调整大小:
为什么在我明确为其分配值时,Path会被分配前一个函数调用中的无效值(在正确分配空字符串之后!)?!!!!!
答案 0 :(得分:2)
您需要使用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; }
}
答案 1 :(得分:2)
TextRenderer.MeasureText
方法是nasty one - 它会更改作为参数传递的实际字符串,因此它会更改DataGridView引用的实际字符串。它实际上使.Net字符串可变。
似乎这个荒谬的方法不会改变字符串的实际Length
,而只是用\0
覆盖其中一个字符以指示字符串的结尾(如null终止)普通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
副本保留为未引用的垃圾回收集。)