2008-09-18 16 views

Respuesta

61

continuación es mi más idiomáticamente WPF, para llevar a todas las funciones de este.Es compatible con prácticamente todo lo que era de esperar, incluyendo:

  • todas las propiedades relacionadas con la fuente, incluyendo estiramiento y estilo
  • alineación del texto (izquierda, derecha, centro, justificar)
  • ajuste de texto
  • texto recorte
  • decoraciones de texto (subrayado, golpean a través etcétera)

Aquí es un simple ejemplo de lo que puede lograrse con ella:

<local:OutlinedTextBlock FontFamily="Verdana" FontSize="20pt" FontWeight="ExtraBold" TextWrapping="Wrap" StrokeThickness="1" Stroke="{StaticResource TextStroke}" Fill="{StaticResource TextFill}"> 
    Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit 
</local:OutlinedTextBlock> 

que se traduce en:

enter image description here

Aquí está el código para el control:

using System; 
using System.ComponentModel; 
using System.Globalization; 
using System.Windows; 
using System.Windows.Documents; 
using System.Windows.Markup; 
using System.Windows.Media; 

[ContentProperty("Text")] 
public class OutlinedTextBlock : FrameworkElement 
{ 
    public static readonly DependencyProperty FillProperty = DependencyProperty.Register(
     "Fill", 
     typeof(Brush), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender)); 

    public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
     "Stroke", 
     typeof(Brush), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender)); 

    public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
     "StrokeThickness", 
     typeof(double), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.AffectsRender)); 

    public static readonly DependencyProperty FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty FontSizeProperty = TextElement.FontSizeProperty.AddOwner(
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty FontStretchProperty = TextElement.FontStretchProperty.AddOwner(
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty FontStyleProperty = TextElement.FontStyleProperty.AddOwner(
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty FontWeightProperty = TextElement.FontWeightProperty.AddOwner(
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
     "Text", 
     typeof(string), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextInvalidated)); 

    public static readonly DependencyProperty TextAlignmentProperty = DependencyProperty.Register(
     "TextAlignment", 
     typeof(TextAlignment), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty TextDecorationsProperty = DependencyProperty.Register(
     "TextDecorations", 
     typeof(TextDecorationCollection), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty TextTrimmingProperty = DependencyProperty.Register(
     "TextTrimming", 
     typeof(TextTrimming), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty TextWrappingProperty = DependencyProperty.Register(
     "TextWrapping", 
     typeof(TextWrapping), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(TextWrapping.NoWrap, OnFormattedTextUpdated)); 

    private FormattedText formattedText; 
    private Geometry textGeometry; 

    public OutlinedTextBlock() 
    { 
     this.TextDecorations = new TextDecorationCollection(); 
    } 

    public Brush Fill 
    { 
     get { return (Brush)GetValue(FillProperty); } 
     set { SetValue(FillProperty, value); } 
    } 

    public FontFamily FontFamily 
    { 
     get { return (FontFamily)GetValue(FontFamilyProperty); } 
     set { SetValue(FontFamilyProperty, value); } 
    } 

    [TypeConverter(typeof(FontSizeConverter))] 
    public double FontSize 
    { 
     get { return (double)GetValue(FontSizeProperty); } 
     set { SetValue(FontSizeProperty, value); } 
    } 

    public FontStretch FontStretch 
    { 
     get { return (FontStretch)GetValue(FontStretchProperty); } 
     set { SetValue(FontStretchProperty, value); } 
    } 

    public FontStyle FontStyle 
    { 
     get { return (FontStyle)GetValue(FontStyleProperty); } 
     set { SetValue(FontStyleProperty, value); } 
    } 

    public FontWeight FontWeight 
    { 
     get { return (FontWeight)GetValue(FontWeightProperty); } 
     set { SetValue(FontWeightProperty, value); } 
    } 

    public Brush Stroke 
    { 
     get { return (Brush)GetValue(StrokeProperty); } 
     set { SetValue(StrokeProperty, value); } 
    } 

    public double StrokeThickness 
    { 
     get { return (double)GetValue(StrokeThicknessProperty); } 
     set { SetValue(StrokeThicknessProperty, value); } 
    } 

    public string Text 
    { 
     get { return (string)GetValue(TextProperty); } 
     set { SetValue(TextProperty, value); } 
    } 

    public TextAlignment TextAlignment 
    { 
     get { return (TextAlignment)GetValue(TextAlignmentProperty); } 
     set { SetValue(TextAlignmentProperty, value); } 
    } 

    public TextDecorationCollection TextDecorations 
    { 
     get { return (TextDecorationCollection)this.GetValue(TextDecorationsProperty); } 
     set { this.SetValue(TextDecorationsProperty, value); } 
    } 

    public TextTrimming TextTrimming 
    { 
     get { return (TextTrimming)GetValue(TextTrimmingProperty); } 
     set { SetValue(TextTrimmingProperty, value); } 
    } 

    public TextWrapping TextWrapping 
    { 
     get { return (TextWrapping)GetValue(TextWrappingProperty); } 
     set { SetValue(TextWrappingProperty, value); } 
    } 

    protected override void OnRender(DrawingContext drawingContext) 
    { 
     this.EnsureGeometry(); 

     drawingContext.DrawGeometry(this.Fill, new Pen(this.Stroke, this.StrokeThickness), this.textGeometry); 
    } 

    protected override Size MeasureOverride(Size availableSize) 
    { 
     this.EnsureFormattedText(); 

     // constrain the formatted text according to the available size 
     // the Math.Min call is important - without this constraint (which seems arbitrary, but is the maximum allowable text width), things blow up when availableSize is infinite in both directions 
     // the Math.Max call is to ensure we don't hit zero, which will cause MaxTextHeight to throw 
     this.formattedText.MaxTextWidth = Math.Min(3579139, availableSize.Width); 
     this.formattedText.MaxTextHeight = Math.Max(0.0001d, availableSize.Height); 

     // return the desired size 
     return new Size(this.formattedText.Width, this.formattedText.Height); 
    } 

    protected override Size ArrangeOverride(Size finalSize) 
    { 
     this.EnsureFormattedText(); 

     // update the formatted text with the final size 
     this.formattedText.MaxTextWidth = finalSize.Width; 
     this.formattedText.MaxTextHeight = finalSize.Height; 

     // need to re-generate the geometry now that the dimensions have changed 
     this.textGeometry = null; 

     return finalSize; 
    } 

    private static void OnFormattedTextInvalidated(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
    { 
     var outlinedTextBlock = (OutlinedTextBlock)dependencyObject; 
     outlinedTextBlock.formattedText = null; 
     outlinedTextBlock.textGeometry = null; 

     outlinedTextBlock.InvalidateMeasure(); 
     outlinedTextBlock.InvalidateVisual(); 
    } 

    private static void OnFormattedTextUpdated(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
    { 
     var outlinedTextBlock = (OutlinedTextBlock)dependencyObject; 
     outlinedTextBlock.UpdateFormattedText(); 
     outlinedTextBlock.textGeometry = null; 

     outlinedTextBlock.InvalidateMeasure(); 
     outlinedTextBlock.InvalidateVisual(); 
    } 

    private void EnsureFormattedText() 
    { 
     if (this.formattedText != null || this.Text == null) 
     { 
      return; 
     } 

     this.formattedText = new FormattedText(
      this.Text, 
      CultureInfo.CurrentUICulture, 
      this.FlowDirection, 
      new Typeface(this.FontFamily, this.FontStyle, this.FontWeight, FontStretches.Normal), 
      this.FontSize, 
      Brushes.Black); 

     this.UpdateFormattedText(); 
    } 

    private void UpdateFormattedText() 
    { 
     if (this.formattedText == null) 
     { 
      return; 
     } 

     this.formattedText.MaxLineCount = this.TextWrapping == TextWrapping.NoWrap ? 1 : int.MaxValue; 
     this.formattedText.TextAlignment = this.TextAlignment; 
     this.formattedText.Trimming = this.TextTrimming; 

     this.formattedText.SetFontSize(this.FontSize); 
     this.formattedText.SetFontStyle(this.FontStyle); 
     this.formattedText.SetFontWeight(this.FontWeight); 
     this.formattedText.SetFontFamily(this.FontFamily); 
     this.formattedText.SetFontStretch(this.FontStretch); 
     this.formattedText.SetTextDecorations(this.TextDecorations); 
    } 

    private void EnsureGeometry() 
    { 
     if (this.textGeometry != null) 
     { 
      return; 
     } 

     this.EnsureFormattedText(); 
     this.textGeometry = this.formattedText.BuildGeometry(new Point(0, 0)); 
    } 
} 
+4

esto sería fantástico si el trazo estuviera fuera de las letras. Gracias por compartir. – discorax

+2

Al usar TemplateBinding con la propiedad Text obtengo una excepción de objeto nulo. Parece ser de la función MeasureOverride donde formattedText es nulo –

+1

Agregué un esto inmediatamente después de this.EnsureFormattedText(); en MeasureOverride –

1

En Blend puede convertir TextBlock en una ruta, y luego usar las propiedades normales de trazo. Pero supongo que querías algo que pudieras hacer dinámico ...

De lo contrario, creo que tendría que ser algún tipo de efecto de mapa de bits o pincel especial.

0

<TextBlock> no tiene atributos decorativos en sí. Lo pondría en un <Lienzo> con un < Rectángulo > y aplicaré el trazo allí.

+1

@ kaiz.net: Frontera! BESO. – user7116

6

que debe envolver el TextBlock con un borde .. algo como esto:

<Border BorderBrush="Purple" BorderThickness="2"> 
     <TextBlock>My fancy TextBlock</TextBlock> 
    </Border> 

en la remota posibilidad de que se preguntan cómo poner un derrame cerebral alrededor de las letras reales (y no todo el TextBlock) que puede quiero ver el uso de un efecto BitmapEffect de Glow y establecer los parámetros en el Glow para que sea el color de trazo que desee, etc. De lo contrario, tendrá que crear algo personalizado.

31

Found It. No es tan fácil de hacer, al parecer, no hay texto de trazo incorporado en WPF (tipo de una gran característica que falta si me preguntas). Primero cree la clase personalizada:

using System; 
using System.Windows.Media; 
using System.Globalization; 
using System.Windows; 
using System.Windows.Markup; 

namespace CustomXaml 
{ 

public class OutlinedText : FrameworkElement, IAddChild 
{ 
    #region Private Fields 

    private Geometry _textGeometry; 

    #endregion 

    #region Private Methods 

    /// <summary> 
    /// Invoked when a dependency property has changed. Generate a new FormattedText object to display. 
    /// </summary> 
    /// <param name="d">OutlineText object whose property was updated.</param> 
    /// <param name="e">Event arguments for the dependency property.</param> 
    private static void OnOutlineTextInvalidated(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     ((OutlinedText)d).CreateText(); 
    } 

    #endregion 


    #region FrameworkElement Overrides 

    /// <summary> 
    /// OnRender override draws the geometry of the text and optional highlight. 
    /// </summary> 
    /// <param name="drawingContext">Drawing context of the OutlineText control.</param> 
    protected override void OnRender(DrawingContext drawingContext) 
    { 
     CreateText(); 
     // Draw the outline based on the properties that are set. 
     drawingContext.DrawGeometry(Fill, new Pen(Stroke, StrokeThickness), _textGeometry); 

    } 

    /// <summary> 
    /// Create the outline geometry based on the formatted text. 
    /// </summary> 
    public void CreateText() 
    { 
     FontStyle fontStyle = FontStyles.Normal; 
     FontWeight fontWeight = FontWeights.Medium; 

     if (Bold == true) fontWeight = FontWeights.Bold; 
     if (Italic == true) fontStyle = FontStyles.Italic; 

     // Create the formatted text based on the properties set. 
     FormattedText formattedText = new FormattedText(
      Text, 
      CultureInfo.GetCultureInfo("en-us"),     
      FlowDirection.LeftToRight, 
      new Typeface(Font, fontStyle, fontWeight, FontStretches.Normal),     
      FontSize, 
      Brushes.Black // This brush does not matter since we use the geometry of the text. 
      ); 

     // Build the geometry object that represents the text. 
     _textGeometry = formattedText.BuildGeometry(new Point(0, 0)); 




     //set the size of the custome control based on the size of the text 
     this.MinWidth = formattedText.Width; 
     this.MinHeight = formattedText.Height; 

    } 

    #endregion 

    #region DependencyProperties 

    /// <summary> 
    /// Specifies whether the font should display Bold font weight. 
    /// </summary> 
    public bool Bold 
    { 
     get 
     { 
      return (bool)GetValue(BoldProperty); 
     } 

     set 
     { 
      SetValue(BoldProperty, value); 
     } 
    } 

    /// <summary> 
    /// Identifies the Bold dependency property. 
    /// </summary> 
    public static readonly DependencyProperty BoldProperty = DependencyProperty.Register(
     "Bold", 
     typeof(bool), 
     typeof(OutlinedText), 
     new FrameworkPropertyMetadata(
      false, 
      FrameworkPropertyMetadataOptions.AffectsRender, 
      new PropertyChangedCallback(OnOutlineTextInvalidated), 
      null 
      ) 
     ); 

    /// <summary> 
    /// Specifies the brush to use for the fill of the formatted text. 
    /// </summary> 
    public Brush Fill 
    { 
     get 
     { 
      return (Brush)GetValue(FillProperty); 
     } 

     set 
     { 
      SetValue(FillProperty, value); 
     } 
    } 

    /// <summary> 
    /// Identifies the Fill dependency property. 
    /// </summary> 
    public static readonly DependencyProperty FillProperty = DependencyProperty.Register(
     "Fill", 
     typeof(Brush), 
     typeof(OutlinedText), 
     new FrameworkPropertyMetadata(
      new SolidColorBrush(Colors.LightSteelBlue), 
      FrameworkPropertyMetadataOptions.AffectsRender, 
      new PropertyChangedCallback(OnOutlineTextInvalidated), 
      null 
      ) 
     ); 

    /// <summary> 
    /// The font to use for the displayed formatted text. 
    /// </summary> 
    public FontFamily Font 
    { 
     get 
     { 
      return (FontFamily)GetValue(FontProperty); 
     } 

     set 
     { 
      SetValue(FontProperty, value); 
     } 
    } 

    /// <summary> 
    /// Identifies the Font dependency property. 
    /// </summary> 
    public static readonly DependencyProperty FontProperty = DependencyProperty.Register(
     "Font", 
     typeof(FontFamily), 
     typeof(OutlinedText), 
     new FrameworkPropertyMetadata(
      new FontFamily("Arial"), 
      FrameworkPropertyMetadataOptions.AffectsRender, 
      new PropertyChangedCallback(OnOutlineTextInvalidated), 
      null 
      ) 
     ); 

    /// <summary> 
    /// The current font size. 
    /// </summary> 
    public double FontSize 
    { 
     get 
     { 
      return (double)GetValue(FontSizeProperty); 
     } 

     set 
     { 
      SetValue(FontSizeProperty, value); 
     } 
    } 

    /// <summary> 
    /// Identifies the FontSize dependency property. 
    /// </summary> 
    public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(
     "FontSize", 
     typeof(double), 
     typeof(OutlinedText), 
     new FrameworkPropertyMetadata(
      (double)48.0, 
      FrameworkPropertyMetadataOptions.AffectsRender, 
      new PropertyChangedCallback(OnOutlineTextInvalidated), 
      null 
      ) 
     ); 


    /// <summary> 
    /// Specifies whether the font should display Italic font style. 
    /// </summary> 
    public bool Italic 
    { 
     get 
     { 
      return (bool)GetValue(ItalicProperty); 
     } 

     set 
     { 
      SetValue(ItalicProperty, value); 
     } 
    } 

    /// <summary> 
    /// Identifies the Italic dependency property. 
    /// </summary> 
    public static readonly DependencyProperty ItalicProperty = DependencyProperty.Register(
     "Italic", 
     typeof(bool), 
     typeof(OutlinedText), 
     new FrameworkPropertyMetadata(
      false, 
      FrameworkPropertyMetadataOptions.AffectsRender, 
      new PropertyChangedCallback(OnOutlineTextInvalidated), 
      null 
      ) 
     ); 

    /// <summary> 
    /// Specifies the brush to use for the stroke and optional hightlight of the formatted text. 
    /// </summary> 
    public Brush Stroke 
    { 
     get 
     { 
      return (Brush)GetValue(StrokeProperty); 
     } 

     set 
     { 
      SetValue(StrokeProperty, value); 
     } 
    } 

    /// <summary> 
    /// Identifies the Stroke dependency property. 
    /// </summary> 
    public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
     "Stroke", 
     typeof(Brush), 
     typeof(OutlinedText), 
     new FrameworkPropertyMetadata(
      new SolidColorBrush(Colors.Teal), 
      FrameworkPropertyMetadataOptions.AffectsRender, 
      new PropertyChangedCallback(OnOutlineTextInvalidated), 
      null 
      ) 
     ); 

    /// <summary> 
    ///  The stroke thickness of the font. 
    /// </summary> 
    public ushort StrokeThickness 
    { 
     get 
     { 
      return (ushort)GetValue(StrokeThicknessProperty); 
     } 

     set 
     { 
      SetValue(StrokeThicknessProperty, value); 
     } 
    } 

    /// <summary> 
    /// Identifies the StrokeThickness dependency property. 
    /// </summary> 
    public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
     "StrokeThickness", 
     typeof(ushort), 
     typeof(OutlinedText), 
     new FrameworkPropertyMetadata(
      (ushort)0, 
      FrameworkPropertyMetadataOptions.AffectsRender, 
      new PropertyChangedCallback(OnOutlineTextInvalidated), 
      null 
      ) 
     ); 

    /// <summary> 
    /// Specifies the text string to display. 
    /// </summary> 
    public string Text 
    { 
     get 
     { 
      return (string)GetValue(TextProperty); 
     } 

     set 
     { 
      SetValue(TextProperty, value); 
     } 
    } 

    /// <summary> 
    /// Identifies the Text dependency property. 
    /// </summary> 
    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
     "Text", 
     typeof(string), 
     typeof(OutlinedText), 
     new FrameworkPropertyMetadata(
      "", 
      FrameworkPropertyMetadataOptions.AffectsRender, 
      new PropertyChangedCallback(OnOutlineTextInvalidated), 
      null 
      ) 
     ); 

    public void AddChild(Object value) 
    { 

    } 

    public void AddText(string value) 
    { 
     Text = value; 
    } 

    #endregion 
} 
} 

La puede hacer referencia en su xaml.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:customControls="clr-namespace:CustomXaml;assembly=CustomXaml"> 
    <Grid> 
     <customControls:OutlinedText x:Name="TextContent" Fill="#ffffffff" FontSize="28"  
Bold="True" Stroke="Black" StrokeThickness="1" Text="Back" Margin="10,0,10,0" 
HorizontalAlignment="Center" VerticalAlignment="Center" Height="Auto" Width="Auto" /> 
    </Grid> 
</Page> 
+0

Esto funcionó muy bien para mí, pero también necesitaba el ajuste de texto y alineación de texto. Esto se hace fácilmente usando las propiedades FormattedText.MaxTextWidth y FormattedText.TextAlignment. – Twelve47

+1

¡Impresionante! Tenga en cuenta que IAddChild está en desuso. En su lugar, atribuya la clase con [ContentProperty ("Texto")], luego puede establecer el texto directamente en XAML como en: El texto! Skrymsli

+0

Esto es increíble. Dado que esta respuesta es un poco vieja ahora, ¿hay alguna otra forma de lograr esto o este sigue siendo el mejor enfoque? +1 –

2

"How to: Create Outlined Text" on MSDN tiene toda la información que necesita.

+3

-1: la respuesta de solo enlace es incorrecta debido a la rotura del enlace. – ANeves

+0

El enlace ya no es válido. – LawMan

+1

Pruebe esto: [link (https://msdn.microsoft.com/en-us/library/vstudio/ms745816 (v = vs.90) .aspx) –

1

Podría simplemente usar una etiqueta en su lugar. Tiene más propiedades con las que puedes jugar. Ejemplo:

<Style x:Key="LeftBorderLabel" TargetType="{x:Type Label}"> 
      <Setter Property="Margin" Value="0" /> 
      <Setter Property="BorderThickness" Value="1,0,0,0" /> 
      <Setter Property="BorderBrush" Value="Blue" /> 
    </Style> 
0

¡Esto me ayudó muchísimo! Por si acaso alguien lo necesita en el futuro, aquí está la versión VB (hecho StrokeThickness un doble y ha añadido una propiedad subrayado):

Imports System 
Imports System.Windows.Media 
Imports System.Globalization 
Imports System.Windows 
Imports System.Windows.Markup 

Namespace CustomXaml 

    Public Class OutlinedText 
     Inherits FrameworkElement 
     Implements IAddChild 

     Private _textGeometry As Geometry 

     Private Shared Sub OnOutlineTextInvalidated(d As DependencyObject, e As DependencyPropertyChangedEventArgs) 
      DirectCast(d, OutlinedText).CreateText() 
     End Sub 

     Protected Overrides Sub OnRender(drawingContext As System.Windows.Media.DrawingContext) 
      CreateText() 
      drawingContext.DrawGeometry(Fill, New Pen(Stroke, StrokeThickness), _textGeometry) 
     End Sub 

     Public Sub CreateText() 
      Dim fontStyle = FontStyles.Normal 
      Dim fontWeight = FontWeights.Medium 
      Dim fontDecoration = New TextDecorationCollection() 

      If Bold Then fontWeight = FontWeights.Bold 
      If Italic Then fontStyle = FontStyles.Italic 
      If Underline Then fontDecoration.Add(TextDecorations.Underline) 

      Dim formattedText = New FormattedText(_ 
           Text, _ 
           CultureInfo.GetCultureInfo("en-us"), _ 
           FlowDirection.LeftToRight, _ 
           New Typeface(Font, fontStyle, fontWeight, FontStretches.Normal), _ 
           FontSize, _ 
           Brushes.Black _ 
           ) 
      formattedText.SetTextDecorations(fontDecoration) 

      _textGeometry = formattedText.BuildGeometry(New Point(0, 0)) 

      Me.MinWidth = formattedText.Width 
      Me.MinHeight = formattedText.Height 
     End Sub 

     Public Property Bold As Boolean 
      Get 
       Return CType(GetValue(BoldProperty), Boolean) 
      End Get 
      Set(value As Boolean) 
       SetValue(BoldProperty, value) 
      End Set 
     End Property 

     Public Shared ReadOnly BoldProperty As DependencyProperty = DependencyProperty.Register(_ 
      "Bold", _ 
      GetType(Boolean), _ 
      GetType(OutlinedText), _ 
      New FrameworkPropertyMetadata(_ 
       False, _ 
       FrameworkPropertyMetadataOptions.AffectsRender, _ 
       New PropertyChangedCallback(AddressOf OnOutlineTextInvalidated), _ 
       Nothing _ 
      ) _ 
     ) 

     Public Property Underline As Boolean 
      Get 
       Return CType(GetValue(UnderlineProperty), Boolean) 
      End Get 
      Set(value As Boolean) 
       SetValue(UnderlineProperty, value) 
      End Set 
     End Property 

     Public Shared ReadOnly UnderlineProperty As DependencyProperty = DependencyProperty.Register(_ 
      "Underline", _ 
      GetType(Boolean), _ 
      GetType(OutlinedText), _ 
      New FrameworkPropertyMetadata(_ 
       False, _ 
       FrameworkPropertyMetadataOptions.AffectsRender, _ 
       New PropertyChangedCallback(AddressOf OnOutlineTextInvalidated), _ 
       Nothing _ 
      ) _ 
     ) 

     Public Property Fill As Brush 
      Get 
       Return CType(GetValue(FillProperty), Brush) 
      End Get 
      Set(value As Brush) 
       SetValue(FillProperty, value) 
      End Set 
     End Property 

     Public Shared ReadOnly FillProperty As DependencyProperty = DependencyProperty.Register(_ 
      "Fill", _ 
      GetType(Brush), _ 
      GetType(OutlinedText), _ 
      New FrameworkPropertyMetadata(_ 
       New SolidColorBrush(Colors.LightSteelBlue), _ 
       FrameworkPropertyMetadataOptions.AffectsRender, _ 
       New PropertyChangedCallback(AddressOf OnOutlineTextInvalidated), _ 
       Nothing _ 
      ) _ 
     ) 

     Public Property Font As FontFamily 
      Get 
       Return CType(GetValue(FontProperty), FontFamily) 
      End Get 
      Set(value As FontFamily) 
       SetValue(FontProperty, value) 
      End Set 
     End Property 

     Public Shared ReadOnly FontProperty As DependencyProperty = DependencyProperty.Register(_ 
      "Font", _ 
      GetType(FontFamily), _ 
      GetType(OutlinedText), _ 
      New FrameworkPropertyMetadata(_ 
       New FontFamily("Arial"), _ 
       FrameworkPropertyMetadataOptions.AffectsRender, _ 
       New PropertyChangedCallback(AddressOf OnOutlineTextInvalidated), _ 
       Nothing _ 
      ) _ 
     ) 

     Public Property FontSize As Double 
      Get 
       Return CType(GetValue(FontSizeProperty), Double) 
      End Get 
      Set(value As Double) 
       SetValue(FontSizeProperty, value) 
      End Set 
     End Property 

     Public Shared ReadOnly FontSizeProperty As DependencyProperty = DependencyProperty.Register(_ 
      "FontSize", _ 
      GetType(Double), _ 
      GetType(OutlinedText), _ 
      New FrameworkPropertyMetadata(_ 
       CDbl(48.0), _ 
       FrameworkPropertyMetadataOptions.AffectsRender, _ 
       New PropertyChangedCallback(AddressOf OnOutlineTextInvalidated), _ 
       Nothing _ 
      ) _ 
     ) 

     Public Property Italic As Boolean 
      Get 
       Return CType(GetValue(ItalicProperty), Boolean) 
      End Get 
      Set(value As Boolean) 
       SetValue(ItalicProperty, value) 
      End Set 
     End Property 

     Public Shared ReadOnly ItalicProperty As DependencyProperty = DependencyProperty.Register(_ 
      "Italic", _ 
      GetType(Boolean), _ 
      GetType(OutlinedText), _ 
      New FrameworkPropertyMetadata(_ 
       False, _ 
       FrameworkPropertyMetadataOptions.AffectsRender, _ 
       New PropertyChangedCallback(AddressOf OnOutlineTextInvalidated), _ 
       Nothing _ 
      ) _ 
     ) 

     Public Property Stroke As Brush 
      Get 
       Return CType(GetValue(StrokeProperty), Brush) 
      End Get 
      Set(value As Brush) 
       SetValue(StrokeProperty, value) 
      End Set 
     End Property 

     Public Shared ReadOnly StrokeProperty As DependencyProperty = DependencyProperty.Register(_ 
      "Stroke", _ 
      GetType(Brush), _ 
      GetType(OutlinedText), _ 
      New FrameworkPropertyMetadata(_ 
       New SolidColorBrush(Colors.Teal), _ 
       FrameworkPropertyMetadataOptions.AffectsRender, _ 
       New PropertyChangedCallback(AddressOf OnOutlineTextInvalidated), _ 
       Nothing _ 
      ) _ 
     ) 

     Public Property StrokeThickness As Double 
      Get 
       Return CType(GetValue(StrokeThicknessProperty), Double) 
      End Get 
      Set(value As Double) 
       SetValue(StrokeThicknessProperty, value) 
      End Set 
     End Property 

     Public Shared ReadOnly StrokeThicknessProperty As DependencyProperty = DependencyProperty.Register(_ 
      "StrokeThickness", _ 
      GetType(Double), _ 
      GetType(OutlinedText), _ 
      New FrameworkPropertyMetadata(_ 
       CDbl(0), _ 
       FrameworkPropertyMetadataOptions.AffectsRender, _ 
       New PropertyChangedCallback(AddressOf OnOutlineTextInvalidated), _ 
       Nothing _ 
      ) _ 
     ) 

     Public Property Text As String 
      Get 
       Return CType(GetValue(TextProperty), String) 
      End Get 
      Set(value As String) 
       SetValue(TextProperty, value) 
      End Set 
     End Property 

     Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register(_ 
      "Text", _ 
      GetType(String), _ 
      GetType(OutlinedText), _ 
      New FrameworkPropertyMetadata(_ 
       "", _ 
       FrameworkPropertyMetadataOptions.AffectsRender, _ 
       New PropertyChangedCallback(AddressOf OnOutlineTextInvalidated), _ 
       Nothing _ 
      ) _ 
     ) 

     Public Sub AddChild(value As Object) Implements System.Windows.Markup.IAddChild.AddChild 

     End Sub 

     Public Sub AddText(text As String) Implements System.Windows.Markup.IAddChild.AddText 
      Me.Text = text 
     End Sub 
    End Class 
End Namespace 
0

Ligera modificación al código de Kent Boogaart que, aunque impresionante, le falta un pequeño detalle . Esto es probablemente un poco impreciso, ya que solo medirá el llenado y no el trazo, pero al agregar un par de líneas al OnRender(), el Viewbox podrá obtener una idea de qué hacer con él (aunque, como con TextBox, no en la vista previa)

protected override void OnRender(DrawingContext drawingContext) 
{ 
    this.EnsureGeometry(); 

    this.Width = this.formattedText.Width; 
    this.Height = this.formattedText.Height; 

    drawingContext.DrawGeometry(this.Fill, new Pen(this.Stroke, this.StrokeThickness), this.textGeometry); 
} 

estoy usando esto con dos capas de texto a fin de la carrera parece ser solamente alrededor del exterior de la siguiente manera. Evidentemente, esto no funcionará de inmediato ya que se refiere a imágenes y fuentes específicas.

<Viewbox Stretch="UniformToFill" Margin="0" Grid.Column="1"> 
    <bd:OutlinedText x:Name="LevelTitleStroke" Text="Level" FontSize="80pt" FontFamily="/fonts/papercuts-2.ttf#Paper Cuts 2" Grid.Row="1" TextAlignment="Center" IsHitTestVisible="False" StrokeThickness="15"> 
     <bd:OutlinedText.Stroke> 
      <ImageBrush ImageSource="/WpfApplication1;component/GrungeMaps/03DarkBlue.jpg" Stretch="None" /> 
     </bd:OutlinedText.Stroke> 
    </bd:OutlinedText> 
</Viewbox> 
<Viewbox Stretch="UniformToFill" Margin="0" Grid.Column="1"> 
    <bd:OutlinedText x:Name="LevelTitleFill" Text="Level" FontSize="80pt" FontFamily="/fonts/papercuts-2.ttf#Paper Cuts 2" Grid.Row="1" TextAlignment="Center" IsHitTestVisible="False"> 
     <bd:OutlinedText.Fill> 
      <ImageBrush ImageSource="/WpfApplication1;component/GrungeMaps/03Red.jpg" Stretch="None" /> 
     </bd:OutlinedText.Fill> 
    </bd:OutlinedText> 
</Viewbox> 
0

Estaba usando la solución de Kent en mi control personalizado. Resultó en una excepción nula cuando se usa la vinculación de plantilla con la propiedad de texto.

tuve que modificar la función MeasureOverride así:

protected override Size MeasureOverride(Size availableSize) 
    { 
     this.EnsureFormattedText(); 

     if (this.formattedText == null) 
     { 
      this.formattedText = new FormattedText(
           (this.Text == null) ? "" : this.Text, 
           CultureInfo.CurrentUICulture, 
           this.FlowDirection, 
           new Typeface(this.FontFamily, this.FontStyle, this.FontWeight, FontStretches.Normal), 
           this.FontSize, 
           Brushes.Black); 
     } 

     // constrain the formatted text according to the available size 
     // the Math.Min call is important - without this constraint (which seems arbitrary, but is the maximum allowable text width), things blow up when availableSize is infinite in both directions 
     this.formattedText.MaxTextWidth = Math.Min(3579139, availableSize.Width); 
     this.formattedText.MaxTextHeight = availableSize.Height; 

     // return the desired size 
     return new Size(this.formattedText.Width, this.formattedText.Height); 
    } 

Debe tenerse en cuenta que no he probado a fondo esto.

0

Estaba tratando de lograr algo similar a esto también. Las clases mencionadas aquí fueron geniales, pero no eran exactamente lo que estaba buscando, porque solo parecía correcto si el texto era lo suficientemente grande. El texto que intentaba mostrar tenía un tamaño de letra de 10 a 11, y el trazo era tan grande que las letras se mezclaron.

Solo para aclarar, se suponía que este texto se superponía en una imagen definida por el usuario, que podía tener colores diferentes, y quería asegurarme de que este texto apareciera.

No sé si esta es la mejor práctica o no, pero esto por lo menos conseguir el aspecto que quería (basado en this article):

<Style x:Key="OutlinedTextBlockOuter" TargetType="TextBlock"> 
    <Setter Property="Foreground" Value="Black" /> 
    <Setter Property="FontSize" Value="10"/> 
    <Setter Property="Effect"> 
     <Setter.Value> 
      <BlurEffect Radius="3.0"/> 
     </Setter.Value> 
    </Setter> 
</Style> 
<Style x:Key="OutlinedTextBlockInner" TargetType="TextBlock"> 
    <Setter Property="Foreground" Value="White" /> 
    <Setter Property="FontSize" Value="10"/> 
</Style> 

Entonces, para los TextBlocks reales, he combinado dos exteriores LABRÓ TextBlocks porque uno era demasiado ligero, y uno interior labrado TextBlock:

<Grid Margin="5"> 
    <TextBlock Style="{StaticResource OutlinedTextBlockOuter}" Text="This is outlined text using BlurEffect"/> 
    <TextBlock Style="{StaticResource OutlinedTextBlockOuter}" Text="This is outlined text using BlurEffect"/> 
    <TextBlock Style="{StaticResource OutlinedTextBlockInner}" Text="This is outlined text using BlurEffect"/> 
</Grid> 

Como alternativa, puede utilizar el DropShadowEffect, que se veía bien con el uso de sólo dos cuadros de texto (aunque la adición de más DropShadowEffects con direcciones diferentes y bajó opacit Y pueden ver aún mejor):

<Grid Margin="5"> 
    <TextBlock Text="This is my outlined text using the DropShadowEffect" FontSize="10" Foreground="White"> 
     <TextBlock.Effect> 
      <DropShadowEffect ShadowDepth="1" BlurRadius="2" Opacity="0.75" Direction="315"/> 
     </TextBlock.Effect> 
    </TextBlock> 
    <TextBlock Text="This is my outlined text using the DropShadowEffect" FontSize="10" Foreground="White"> 
     <TextBlock.Effect> 
      <DropShadowEffect ShadowDepth="1" BlurRadius="2" Opacity="0.75" Direction="135"/> 
     </TextBlock.Effect> 
    </TextBlock> 
</Grid> 
1

Si se aplica para cualquier persona, aquí una solución sencilla utilizando sólo XAML, no Sureif mejor o peor en cuanto a rendimiento, pero para asegurarse de que se vea mejor que cualquier otra solución anterior (en mi caso). I Warp en ContentContro l Estilo (y plantilla), siguiendo este ejemplo Old School :) http://oldschooldotnet.blogspot.co.il/2009/02/fancy-fonts-in-xaml-silverlight-and-wpf.html

<Style x:Key="OutlinedText" TargetType="{x:Type ContentControl}"> 
    <!-- Some Style Setters --> 
    <Setter Property="Content" Value="Outlined Text"/> 
    <Setter Property="Padding" Value="0"/> 
    <!-- Border Brush Must be equal '0' because TextBlock that emulate the stroke will using the BorderBrush as to define 'Stroke' color--> 
    <Setter Property="BorderThickness" Value="0"/> 
    <!-- Border Brush define 'Stroke' Color--> 
    <Setter Property="BorderBrush" Value="White"/> 
    <Setter Property="Foreground" Value="Black"/> 
    <Setter Property="FontSize" Value="24"/> 
    <Setter Property="FontFamily" Value="Seoge UI Bold"/> 
    <Setter Property="HorizontalContentAlignment" Value="Center"/> 
    <Setter Property="VerticalContentAlignment" Value="Center"/> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type ContentControl}"> 
       <Canvas Width="{Binding ActualWidth, ElementName=FillText}" Height="{Binding ActualHeight, ElementName=FillText}"> 
        <Canvas.Resources> 
         <!-- Style to ease the duplication of Text Blocks that emulate the stroke: Binding to one element (or to template) is the first part of the Trick --> 
         <Style x:Key="OutlinedTextStrokeTextBlock_Style" TargetType="{x:Type TextBlock}"> 
          <Setter Property="Text" Value="{Binding Text, ElementName=FillText}"/> 
          <Setter Property="FontSize" Value="{Binding FontSize, ElementName=FillText}"/> 
          <Setter Property="FontFamily" Value="{Binding FontFamily, ElementName=FillText}"/> 
          <Setter Property="FontStyle" Value="{Binding FontStyle, ElementName=FillText}"/> 
          <Setter Property="FontWeight" Value="{Binding FontWeight, ElementName=FillText}"/> 
          <Setter Property="Padding" Value="{Binding TextAlignment, ElementName=Padding}"/> 
          <Setter Property="TextAlignment" Value="{Binding TextAlignment, ElementName=FillText}"/> 
          <Setter Property="VerticalAlignment" Value="{Binding VerticalAlignment, ElementName=FillText}"/> 
         </Style> 
        </Canvas.Resources> 
        <!-- Offseting the Text block will create the outline, the margin is the Stroke Width--> 
        <TextBlock Foreground="{TemplateBinding BorderBrush}" Margin="-1,0,0,0" Style="{DynamicResource OutlinedTextStrokeTextBlock_Style}"/> 
        <TextBlock Foreground="{TemplateBinding BorderBrush}" Margin="0,-1,0,0" Style="{DynamicResource OutlinedTextStrokeTextBlock_Style}"/> 
        <TextBlock Foreground="{TemplateBinding BorderBrush}" Margin="0,0,-1,0" Style="{DynamicResource OutlinedTextStrokeTextBlock_Style}"/> 
        <TextBlock Foreground="{TemplateBinding BorderBrush}" Margin="0,0,0,-1" Style="{DynamicResource OutlinedTextStrokeTextBlock_Style}"/> 
        <!-- Base TextBlock Will be the Fill --> 
        <TextBlock x:Name="FillText" Text="{TemplateBinding Content}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" 
           FontStyle="{TemplateBinding FontStyle}" FontWeight="{TemplateBinding FontWeight}" Padding="0" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
           TextAlignment="{TemplateBinding HorizontalContentAlignment}" 
           Style="{DynamicResource TbMediaOverlay_Style}"/> 
       </Canvas> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 
0

he tenido que añadir a esta MeasureOverride por lo que mostraría líneas individuales de texto mientras se utiliza el redondeo del diseño. Sin embargo, funcionó bien cuando el texto se estaba completando.

// return the desired size 
return new Size(Math.Ceiling(_FormattedText.Width), Math.Ceiling(_FormattedText.Height)); 
19

que modifica la respuesta más votado con varias correcciones, incluyendo:

  • Fix tan textos con una sola línea mostrarían al utilizar UseLayoutRounding.

  • Los contornos se mostrarían fuera del texto en lugar de en el medio del borde .

  • El lápiz se crea solo una vez en lugar de en cada renderizado.

  • Repare para que no se bloquee cuando el texto se establece en nulo.

  • Reordene el contorno para usar tapas redondas adecuadas.

using System; 
using System.ComponentModel; 
using System.Globalization; 
using System.Windows; 
using System.Windows.Documents; 
using System.Windows.Markup; 
using System.Windows.Media; 

[ContentProperty("Text")] 
public class OutlinedTextBlock : FrameworkElement 
{ 
    private void UpdatePen() { 
     _Pen = new Pen(Stroke, StrokeThickness) { 
      DashCap = PenLineCap.Round, 
      EndLineCap = PenLineCap.Round, 
      LineJoin = PenLineJoin.Round, 
      StartLineCap = PenLineCap.Round 
     }; 

     InvalidateVisual(); 
    } 

    public static readonly DependencyProperty FillProperty = DependencyProperty.Register(
     "Fill", 
     typeof(Brush), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender)); 

    public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
     "Stroke", 
     typeof(Brush), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender, StrokePropertyChangedCallback)); 

    private static void StrokePropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) { 
     (dependencyObject as OutlinedTextBlock)?.UpdatePen(); 
    } 

    public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
     "StrokeThickness", 
     typeof(double), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.AffectsRender, StrokePropertyChangedCallback)); 

    public static readonly DependencyProperty FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty FontSizeProperty = TextElement.FontSizeProperty.AddOwner(
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty FontStretchProperty = TextElement.FontStretchProperty.AddOwner(
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty FontStyleProperty = TextElement.FontStyleProperty.AddOwner(
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty FontWeightProperty = TextElement.FontWeightProperty.AddOwner(
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
     "Text", 
     typeof(string), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextInvalidated)); 

    public static readonly DependencyProperty TextAlignmentProperty = DependencyProperty.Register(
     "TextAlignment", 
     typeof(TextAlignment), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty TextDecorationsProperty = DependencyProperty.Register(
     "TextDecorations", 
     typeof(TextDecorationCollection), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty TextTrimmingProperty = DependencyProperty.Register(
     "TextTrimming", 
     typeof(TextTrimming), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(OnFormattedTextUpdated)); 

    public static readonly DependencyProperty TextWrappingProperty = DependencyProperty.Register(
     "TextWrapping", 
     typeof(TextWrapping), 
     typeof(OutlinedTextBlock), 
     new FrameworkPropertyMetadata(TextWrapping.NoWrap, OnFormattedTextUpdated)); 

    private FormattedText _FormattedText; 
    private Geometry _TextGeometry; 
    private Pen _Pen; 

    public Brush Fill 
    { 
     get { return (Brush)GetValue(FillProperty); } 
     set { SetValue(FillProperty, value); } 
    } 

    public FontFamily FontFamily 
    { 
     get { return (FontFamily)GetValue(FontFamilyProperty); } 
     set { SetValue(FontFamilyProperty, value); } 
    } 

    [TypeConverter(typeof(FontSizeConverter))] 
    public double FontSize 
    { 
     get { return (double)GetValue(FontSizeProperty); } 
     set { SetValue(FontSizeProperty, value); } 
    } 

    public FontStretch FontStretch 
    { 
     get { return (FontStretch)GetValue(FontStretchProperty); } 
     set { SetValue(FontStretchProperty, value); } 
    } 

    public FontStyle FontStyle 
    { 
     get { return (FontStyle)GetValue(FontStyleProperty); } 
     set { SetValue(FontStyleProperty, value); } 
    } 

    public FontWeight FontWeight 
    { 
     get { return (FontWeight)GetValue(FontWeightProperty); } 
     set { SetValue(FontWeightProperty, value); } 
    } 

    public Brush Stroke 
    { 
     get { return (Brush)GetValue(StrokeProperty); } 
     set { SetValue(StrokeProperty, value); } 
    } 

    public double StrokeThickness 
    { 
     get { return (double)GetValue(StrokeThicknessProperty); } 
     set { SetValue(StrokeThicknessProperty, value); } 
    } 

    public string Text 
    { 
     get { return (string)GetValue(TextProperty); } 
     set { SetValue(TextProperty, value); } 
    } 

    public TextAlignment TextAlignment 
    { 
     get { return (TextAlignment)GetValue(TextAlignmentProperty); } 
     set { SetValue(TextAlignmentProperty, value); } 
    } 

    public TextDecorationCollection TextDecorations 
    { 
     get { return (TextDecorationCollection)GetValue(TextDecorationsProperty); } 
     set { SetValue(TextDecorationsProperty, value); } 
    } 

    public TextTrimming TextTrimming 
    { 
     get { return (TextTrimming)GetValue(TextTrimmingProperty); } 
     set { SetValue(TextTrimmingProperty, value); } 
    } 

    public TextWrapping TextWrapping 
    { 
     get { return (TextWrapping)GetValue(TextWrappingProperty); } 
     set { SetValue(TextWrappingProperty, value); } 
    } 

    public OutlinedTextBlock() { 
     UpdatePen(); 
     TextDecorations = new TextDecorationCollection(); 
    } 

    protected override void OnRender(DrawingContext drawingContext) { 
     EnsureGeometry(); 

     drawingContext.DrawGeometry(null, _Pen, _TextGeometry); 
     drawingContext.DrawGeometry(Fill, null, _TextGeometry); 
    } 

    protected override Size MeasureOverride(Size availableSize) { 
     EnsureFormattedText(); 

     // constrain the formatted text according to the available size 

     double w = availableSize.Width; 
     double h = availableSize.Height; 

     // the Math.Min call is important - without this constraint (which seems arbitrary, but is the maximum allowable text width), things blow up when availableSize is infinite in both directions 
     // the Math.Max call is to ensure we don't hit zero, which will cause MaxTextHeight to throw 
     _FormattedText.MaxTextWidth = Math.Min(3579139, w); 
     _FormattedText.MaxTextHeight = Math.Max(0.0001d, h); 

     // return the desired size 
     return new Size(Math.Ceiling(_FormattedText.Width), Math.Ceiling(_FormattedText.Height)); 
    } 

    protected override Size ArrangeOverride(Size finalSize) { 
     EnsureFormattedText(); 

     // update the formatted text with the final size 
     _FormattedText.MaxTextWidth = finalSize.Width; 
     _FormattedText.MaxTextHeight = Math.Max(0.0001d, finalSize.Height); 

     // need to re-generate the geometry now that the dimensions have changed 
     _TextGeometry = null; 

     return finalSize; 
    } 

    private static void OnFormattedTextInvalidated(DependencyObject dependencyObject, 
     DependencyPropertyChangedEventArgs e) { 
     var outlinedTextBlock = (OutlinedTextBlock)dependencyObject; 
     outlinedTextBlock._FormattedText = null; 
     outlinedTextBlock._TextGeometry = null; 

     outlinedTextBlock.InvalidateMeasure(); 
     outlinedTextBlock.InvalidateVisual(); 
    } 

    private static void OnFormattedTextUpdated(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { 
     var outlinedTextBlock = (OutlinedTextBlock)dependencyObject; 
     outlinedTextBlock.UpdateFormattedText(); 
     outlinedTextBlock._TextGeometry = null; 

     outlinedTextBlock.InvalidateMeasure(); 
     outlinedTextBlock.InvalidateVisual(); 
    } 

    private void EnsureFormattedText() { 
     if (_FormattedText != null) { 
      return; 
     } 

     _FormattedText = new FormattedText(
      Text ?? "", 
      CultureInfo.CurrentUICulture, 
      FlowDirection, 
      new Typeface(FontFamily, FontStyle, FontWeight, FontStretch), 
      FontSize, 
      Brushes.Black); 

     UpdateFormattedText(); 
    } 

    private void UpdateFormattedText() { 
     if (_FormattedText == null) { 
      return; 
     } 

     _FormattedText.MaxLineCount = TextWrapping == TextWrapping.NoWrap ? 1 : int.MaxValue; 
     _FormattedText.TextAlignment = TextAlignment; 
     _FormattedText.Trimming = TextTrimming; 

     _FormattedText.SetFontSize(FontSize); 
     _FormattedText.SetFontStyle(FontStyle); 
     _FormattedText.SetFontWeight(FontWeight); 
     _FormattedText.SetFontFamily(FontFamily); 
     _FormattedText.SetFontStretch(FontStretch); 
     _FormattedText.SetTextDecorations(TextDecorations); 
    } 

    private void EnsureGeometry() { 
     if (_TextGeometry != null) { 
      return; 
     } 

     EnsureFormattedText(); 
     _TextGeometry = _FormattedText.BuildGeometry(new Point(0, 0)); 
    } 
} 
+1

Gracias por compartir esto agrega la perfección a la solución anterior. ¿Por qué nadie te votó? – Luca

+0

Supongo que la pregunta es demasiado antigua, WPF ya no está tan caliente o una combinación de ambos? :) –

+1

¡WPF está CALIENTE! entonces solo queda la primera oportunidad – Luca

Cuestiones relacionadas