Форматировать ячейку DataGridView без изменения базового значения?
-
05-07-2019 - |
Вопрос
У меня есть несвязанный DataGridView (в VS 2008), один столбец которого содержит путь к файлу. Я хотел бы отформатировать строку, используя класс TextRenderer в событии ColumnWidthChanged без фактического изменения базового значения. Проблема в том, что содержимое таблицы сохраняется, когда форма закрыта, и я не хочу сохранять отформатированное значение. Я думаю, что я слишком глубоко, чтобы увидеть очевидное решение, поэтому я полагаюсь на вас, ребята, чтобы указать на это: -).
Идея состоит в том, чтобы отобразить это:
C: \ Program Files \ Microsoft Visual Studio 8 \ SDK \ v2.0 \ Bin \ gacutil.exe
... как это (в зависимости от ширины столбца):
C: \ Program Files \ Microso & # 8230; \ gacutil.exe
<Ч>Похоже, я говорил слишком рано. Я получаю некоторые очень странные результаты от TextRenderer.MeasureText (). Если я жестко закодировал значение пути как " C: \ Documents and Settings \ jluce \ Мои документы \ Загрузки " это заканчивается как 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;
Первый столбец изменения размера (см. # в комментариях выше):
<Ол>Изменение размера во второй раз.
<Ол>Почему Path присваивает неверное значение из предыдущего вызова функции (после правильного назначения пустой строки!), когда я явно присваиваю ему значение? !!!!!
Решение
TextRenderer.MeasureText
является nasty one - изменяет фактическую строку, переданную в качестве параметра, поэтому она изменяет фактическую строку, на которую ссылается DataGridView. Это на самом деле делает строку .Net изменяемой .
Также кажется, что этот нелепый метод не меняет фактическую длину
строки, а просто перезаписывает один из символов с помощью \ 0
, указывая конец строка (как строки с нулевым символом в конце в простом C). Это забавные вещи!
Это может серьезно повлиять на стабильность вашего приложения. Если принять во внимание, что .Net использует интернирование строк вы можете начать получать всевозможные странные результаты, поскольку заметили, что ваши строковые константы больше не кажутся постоянными.
Первый шаг - создать копию вашей строки (новый экземпляр с такими же символами):
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; }
}