@ Ответ BrokenGlass - отличный, но в зависимости от характеристик вашего приложения вы можете обнаружить, что вы получаете лучшую производительность с помощью бинарного поиска. Если большинство ваших строк вписывается в доступную ширину, или, как правило, их нужно обрезать только одним или двумя символами, тогда лучше использовать линейный поиск. Однако, если у вас много длинных строк, которые будут сильно урезаны, следующий двоичный поиск будет работать хорошо.
Обратите внимание, что и availableWidth, и fontSize указаны в независимых от устройства единицах (1/96 дюйма). Кроме того, используйте TextFormattingMode, который соответствует способу рисования текста.
public static string TruncateTextToFitAvailableWidth(
string text,
double availableWidth,
string fontName,
double fontSize)
{
if(availableWidth <= 0)
return string.Empty;
Typeface typeface = new Typeface(fontName);
int foundCharIndex = BinarySearch(
text.Length,
availableWidth,
predicate: (idxValue1, value2) =>
{
FormattedText ft = new FormattedText(
text.Substring(0, idxValue1 + 1),
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
typeface,
fontSize,
Brushes.Black,
numberSubstitution: null,
textFormattingMode: TextFormattingMode.Ideal);
return ft.WidthIncludingTrailingWhitespace.CompareTo(value2);
});
int numChars = (foundCharIndex < 0) ? ~foundCharIndex : foundCharIndex + 1;
return text.Substring(0, numChars);
}
/**
<summary>
See <see cref="T:System.Array.BinarySearch"/>. This implementation is exactly the same,
except that it is not bound to any specific type of collection. The behavior of the
supplied predicate should match that of the T.Compare method (for example,
<see cref="T:System.String.Compare"/>).
</summary>
*/
public static int BinarySearch<T>(
int length,
T value,
Func<int, T, int> predicate) // idxValue1, value2, compareResult
{
return BinarySearch(0, length, value, predicate);
}
public static int BinarySearch<T>(
int index,
int length,
T value,
Func<int, T, int> predicate)
{
int lo = index;
int hi = (index + length) - 1;
while(lo <= hi)
{
int mid = lo + ((hi - lo) / 2);
int compareResult = predicate(mid, value);
if(compareResult == 0)
return mid;
else if(compareResult < 0)
lo = mid + 1;
else
hi = mid - 1;
}
return ~lo;
}