2011-01-21 45 views
5

Necesito mostrar las palabras en un lienzo de WPF de forma que quepan perfectamente en cuadros predefinidos.Renderizar texto en WPF para que se ajuste perfectamente a un rectángulo determinado

Una caja generalmente contiene una sola línea de texto, de una letra a unas pocas palabras.

El texto dentro de una casilla debe ser lo más grande posible, es decir, tocar todos los bordes de la caja (excepto tal vez porque causaría demasiada distorsión de texto debido a una proporción anormal de caja/altura).

No pude encontrar una buena manera de calcular la altura, escala y compensación de fuente adecuadas, según el contenido del texto.

¡Una primera solución en la que la relación de ancho/alto del texto original no se puede cambiar ya sería muy agradable!

Me gustaría utilizar elementos TextBlock, pero cualquier otra cosa que funcione debería estar bien.

Respuesta

5

Como dijo la respuesta de Robery Levy, puede usar un Viewbox para lograrlo. Sin embargo, el texto en sí no se extenderá, por lo que aún tendrá un "margen" en cero o más lados dependiendo de su texto (como notó). Para solucionar este problema, puede crear un control personalizado que construya un Geometry desde un FormattedText y luego dibujarlo con DrawGeometry en OnRender. Notará cómo la calidad del texto mejora con un FontSize más grande. Un texto muy pequeño (por ejemplo FontSize="10") no se verá muy agudo en un gran Viewbox por lo que tendrá que experimentar un poco

enter image description here

Parte de la muestra Xaml

<Canvas Background="Black"> 
    <Viewbox Canvas.Left="10" Canvas.Top="10" 
      Stretch="Fill" Width="200" Height="50"> 
     <Border Background="Red"> 
      <local:StretchText Text="Text" Foreground="Green" FontSize="100"/> 
     </Border> 
    </Viewbox> 
    <Viewbox Canvas.Left="230" Canvas.Top="10" 
      Stretch="Fill" Width="200" Height="50"> 
     <Border Background="Red"> 
      <local:StretchText Text="B" Foreground="Green" FontSize="500"/> 
     </Border> 
    </Viewbox> 
</Canvas> 

texto extendido .cs

public class StretchText : Control 
{ 
    protected override void OnRender(DrawingContext drawingContext) 
    { 
     FormattedText formattedText = new FormattedText(
      Text, 
      CultureInfo.GetCultureInfo("en-us"), 
      FlowDirection.LeftToRight, 
      new Typeface(FontFamily, FontStyle, FontWeight, FontStretches.Normal), 
      FontSize, 
      Foreground); 

     Geometry textGeometry = formattedText.BuildGeometry(new Point(0, 0)); 
     this.MinWidth = textGeometry.Bounds.Width; 
     this.MinHeight = textGeometry.Bounds.Height; 

     TranslateTransform translateTransform = new TranslateTransform(); 
     translateTransform.X = -textGeometry.Bounds.Left; 
     translateTransform.Y = -textGeometry.Bounds.Top; 
     drawingContext.PushTransform(translateTransform); 
     drawingContext.DrawGeometry(Foreground, new Pen(Foreground, 1.0), textGeometry); 
    } 

    public string Text 
    { 
     get { return (string)GetValue(TextProperty); } 
     set { SetValue(TextProperty, value); } 
    } 
    public static readonly DependencyProperty TextProperty = 
     DependencyProperty.Register("Text", 
     typeof(string), 
     typeof(StretchText), 
     new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsRender)); 
} 
+0

¡Gracias! Lo probé y funciona bastante bien. Mientras tanto, encontré una solución alternativa: medir los elementos de texto a través de un objeto FormattedText temporal (gracias a las propiedades "Ancho", "Extensión" y "Extender después"), luego aplicar un Scale + TranslateTransform a cada elemento en consecuencia. Sin embargo, tiene dos desventajas: los bloques de texto reales se vuelven demasiado grandes (desordenar la información sobre herramientas) y el renderizado no es tan rápido como me gustaría. – Jem

+1

@Jem: No hay problema :) ¿Cómo fue el tiempo de renderizado entre nuestras soluciones? ¿Fue "lento" en ambos casos? Intenté con 10 o más 'StretchText' simultáneamente en una' Grilla' y luego redimensioné la 'Ventana' rápidamente. Parecía que funcionaba muy bien, pero 'DrawGeometry' es conocido por ser bastante lento –

+0

el número de palabras para mostrar es de aproximadamente uno o dos mil, pero cambiar el tamaño de la página es lo suficientemente suave con su solución. Yo diría que es aproximadamente 3 veces más rápido que el mío, y es estable (sin "retrasos").Sin embargo, la calidad del texto no es tan nítida para textos pequeños (probablemente porque ya no es "texto", sino "geometría"), pero es lo suficientemente bueno. Idealmente, me gustaría obtener un mejor rendimiento y la mejor calidad de texto posible, pero su solución es el mejor compromiso por el momento. – Jem

4
+0

Gracias , Acabo de tratar. Interesante, pero no hace exactamente lo que necesito: no es consciente del contenido del texto tal como está. Por ejemplo, todavía tengo márgenes debajo del texto a menos que una letra cruce la línea de base (como 'g', 'p', 'y' 'q'). Realmente necesito que el cuadro de entrada sea el texto "caja de bouding". – Jem

0

se puede consultar el artículo de Charles Petzold "Render Text on a Path with WPF". Lamentablemente, no puedo actualizar mis conocimientos sobre el tema en este momento debido a que algo va mal en el sitio de MSDN, pero me describió cómo escalar el texto dentro de la ruta.

Cuestiones relacionadas