@ respuesta de BrokenGlass es grande, pero dependiendo de las características de su aplicación , puede encontrar que obtiene un mejor rendimiento con una búsqueda binaria. Si la mayoría de sus cadenas encajan en el ancho disponible, o generalmente solo necesitan ser recortadas por un carácter o dos, entonces una búsqueda lineal es lo mejor. Sin embargo, si tiene muchas cadenas largas que se truncarán severamente, la siguiente búsqueda binaria funcionará bien.
Tenga en cuenta que tanto availableWidth como fontSize se especifican en unidades independientes del dispositivo (1/96 de pulgada). Además, use el TextFormattingMode que coincida con la forma en que dibuja su texto.
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;
}
Excelente comienzo, ¿tenemos alguna idea de cómo hacer todo lo contrario o necesito aplicar algún tipo de división? y conquistar la estrategia? es decir, mida "¿Soy demasiado largo para caber en este espacio?" y luego, si> ancho disponible, mida "¿Soy demasiado largo?" y si es demasiado corto, intente algo entre medio? – Ian
@Ian: debería ser sencillo escribir un método que devuelva el número de caracteres que se ajusta a un ancho determinado, comenzaría con algo así como mi edición anterior (obviamente simplificada), y si el rendimiento es un problema, vaya a algo más complicado - No he hecho ninguna medición. – BrokenGlass
Sí. ¿Cuán exacto es cada char de una cuerda desconocida? Imposible, solo puede ser "asumido" (promediado). – TomTom