Форматировать ячейку DataGridView без изменения базового значения?

StackOverflow https://stackoverflow.com/questions/1609026

Вопрос

У меня есть несвязанный 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;

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

<Ол>
  • После этой строки путь содержит " ".
  • После этой строки путь содержит строку, как показано выше.
  • Путь содержит усеченный путь к файлу, как и должно быть (то есть " C: \ Documents and Setti ... \ Downloads ")
  • Изменение размера во второй раз.

    <Ол>
  • После этой строки Path содержит " " ;, как и должно быть.
  • После этой строки путь содержит " C: \ Documents and Set ... \ Downloads \ 0 Documents \ Downloads " ;, который был недопустимым значением из предыдущей итерации, перед тем как я удалил недопустимые символы (обозначенные здесь как '\ 0' ) !!
  • Теперь путь FUBAR, потому что я начал с испорченной строки, и это только ухудшается.
  • Почему 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; }
    }
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top