Я искал способ вставить замещающий знак в путь C# и нашел ответ здесь на stackoverflow: Эллипсис Пути C# без вызова API Win32
Используя версии 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) Получившая строка является narfed (путь является усеченным как ожидалось, но сопровождается тем, что похоже на пустой указатель завершения 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);
}
}
}
Святая милая, вы нашли огромную ошибку. 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. Документально подтверждено, что это не имеет никакого эффекта.
Моя исходная строка изменена, чтобы быть идентичной выходной строке.
Вы попросили, чтобы это произошло, указав TextFormatFlags.ModifyString
, что в документации сказано
Изменяет указанную строку , чтобы она соответствовала отображаемому тексту. Это значение не действует, если также не указаны EndEllipsis или PathEllipsis.
Это (на мой взгляд) необычный способ работы вызова .NET Framework, но в нем ясно сказано, что он будет это делать.И "исходная" строка, и "выходная" строка в конечном итоге изменяются, потому что строка
является ссылочным типом (хотя обычно с семантикой неизменяемого значения) - когда вы говорите
string ellipsisedPath = OriginalPath;
, вы фактически просто делаете ellipsisedPath
относится к тому же экземпляру строки, что и OriginalPath
. Когда этот экземпляр будет изменен вызовом API, обе ссылки на него увидят изменение.
Что касается
, путь усекается, как и ожидалось, но за ним следует то, что выглядит как завершающий ноль в стиле C, и фрагмент исходного пути
, я предполагаю, что абстракция, которую предоставляет эта управляемая оболочка вокруг вызов Win32 API несколько нечеткий, поскольку абстракции склонны к существованию - это не защищает вас от того факта, что основной вызов работает со строками в стиле C. Возможно, вам придется разобраться с собой.