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