Добавление многоточия в путь в программе WinForms без вызова Win32 API (пересмотрено) - PullRequest
5 голосов
/ 14 апреля 2010

Я искал способ вставить многоточие в путь C # и нашел здесь ответ на stackoverflow: C # Path Ellipsis без вызова Win32 API

Используя RTM-версии VS2010 и .Net 4.0, я не смог заставить предложенный метод работать. Я искал в сети и нашел пример кода, который использует тот же метод, но он не прошел аналогичным образом.

Вы можете увидеть строку, которую я пытаюсь сократить, в моем коде ниже.

После вызова метода MeasureText входная строка (OriginalName) и выходная строка (ellipsisedName) выглядят следующим образом:

d: \ ABCD \ EFGH \ IJKL \ MNOP \ QRST \ ... \ test.txt \ 0F \ GHIJ \ KLMN \ OPQR \ STIV \ WXYZ \ test.txt

Две проблемы:

1) Результирующая строка является узаконенной (путь усекается, как и ожидалось, но за ним следует то, что выглядит как завершающий ноль в стиле C и фрагмент исходного пути).

2) Моя исходная строка заменена на идентичную выходной строке.

Я что-то не так делаю?

namespace WindowsFormsApplication2 {
   public partial class Form1 : Form {
      public Form1()
      {
         InitializeComponent();

         string OriginalPath = @"d:\abcd\efgh\ijkl\mnop\qrst\uvwx\yzAB\CDEF\GHIJ\KLMN\OPQR\STIV\WXYZ\test.txt";
         string ellipsisedPath = OriginalPath;

         Size proposedSize = new Size(label1.Width, label1.Height);

         TextRenderer.MeasureText(ellipsisedPath, label1.Font, proposedSize, TextFormatFlags.ModifyString | TextFormatFlags.PathEllipsis);
      }
   }
}

Ответы [ 2 ]

4 голосов
/ 15 апреля 2010

Святая моли, ты нашел колючку жука. P / Invoke, используемый внутри класса TextRenderer, который вызывает DrawTextEx (), не работает. Эта функция API записывает обратно в строку, что ей разрешено делать, поскольку аргумент cchText является LPTSTR, а не LPCTSTR. Это уничтожает содержимое строки .NET для обеих переменных, потому что строка интернирована.

Эта ошибка не относится к .NET 4.0, я также вижу ее неправильно в ReferenceSource для .NET 3.5 SP1 и могу воспроизвести ее на VS2008 Беда во внутренней функции WindowsGraphics.MeasureText. Вы можете сообщить об ошибке на connect.microsoft.com.

Возможный обходной путь - изменить строку, чтобы она копировалась и не влияла на оригинал:

  string ellipsisedPath = OriginalPath + '\0';

Но лучший обходной путь в этом случае - просто не передавать параметр ModifyString, он не имеет смысла. Что также безопаснее, есть возможность уничтожить кучу мусора с первым обходным путем. Исправление для Microsoft аналогично просто, оно должно просто замаскировать параметр ModifyString. Документально не имеет никакого эффекта.

2 голосов
/ 14 апреля 2010

Моя исходная строка изменена, чтобы быть идентичной выходной строке.

Вы просили, чтобы это произошло, указав TextFormatFlags.ModifyString, что в документах написано

Изменяет указанную строку в соответствии с отображаемым текстом. Это значение не имеет никакого эффекта, если также не указаны EndEllipsis или PathEllipsis.

Это (на мой взгляд) необычный способ работы вызова .NET Framework, но в нем четко сказано, что он это сделает. И «оригинальная» строка, и «выходная» строка в конечном итоге изменяются, потому что string является ссылочным типом (хотя обычно с семантикой неизменяемых значений) - когда вы говорите

string ellipsisedPath = OriginalPath;

вы на самом деле просто заставляете ellipsisedPath ссылаться на тот же экземпляр строки, что и OriginalPath. Когда этот экземпляр модифицируется вызовом API, обе ссылки на него увидят изменение.

Что касается

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

Я полагаю, что абстракция, которую эта управляемая оболочка предоставляет для вызова Win32 API, несколько утечка, поскольку абстракции склонны к тому, что она не оградит вас от того факта, что основной вызов работает со строками в стиле C. Возможно, вам придется иметь дело с самим собой.

...