2009-10-22 2 views
2

У меня есть несвязанный DataGridView (в VS 2008), из которых один столбец содержит путь к файлу. Я хотел бы форматировать строку, используя класс TextRenderer, в событии ColumnWidthChanged, не изменяя основное значение. Проблема в том, что содержимое таблицы сохраняется, когда форма закрыта, и я не хочу сохранять форматированное значение. Я думаю, что я слишком глубоко, чтобы увидеть очевидное решение, поэтому я в зависимости от вас, ребята, хочу указать на это :-).Формат DataGridView Cell без изменения базового значения?

Идея заключается в том, чтобы показать это:

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

Этот jus t продолжает становиться более странным !!

Мне удалось исправить проблему искаженной строки путем повторения каждого символа и удаления плохих. Однако теперь у меня есть еще более сумасшедшая проблема. Локальная переменная, которую я назначаю в обработчике событий, сохраняет значение между вызовами.

Вот соответствующий код:

 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; 

Первый раз изменение размера столбца (см # 's в приведенных выше комментариях):

  1. После этой линии Путь содержит "".
  2. После этой строки Путь содержит строку так, как она отображается выше.
  3. Путь содержит укороченный путь к файлу, как он должен (т.е. "C: \ Documents и Setti ... \ Downloads")

Второй раз подгоняя:

  1. После этой линии Путь содержит "" , как это должно.
  2. После этой строки Путь содержит «C: \ Documents and Set ... \ Downloads \ 0 Documents \ Downloads», который был недопустимым значением из предыдущей итерации, прежде чем я удалил недопустимые символы (здесь видны как «\ 0 «) !!
  3. Теперь путь FUBAR, потому что я начал с испорченной струны, и это только ухудшается.

Зачем было назначено значение Path для недопустимого значения из предыдущего вызова функции (после правильного назначения пустой строки!), Когда я явно назначаю ему значение? !!!!!

+0

См. Мой «ответ» ниже для более подробной информации о проблеме ... – jluce50

ответ

2

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

+0

Спасибо, это похоже на работу! Я согласен, этот метод странный. Очень небольшая документация и очень непредсказуемые результаты. – jluce50

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

У меня было ощущение, что это что-то простое. Спасибо!! – jluce50