2008-09-18 36 views

Trả lời

61

Dưới đây là tôi idiomatically hơn WPF, đầy đủ tính năng take về vấn đề này.Nó hỗ trợ khá nhiều tất cả mọi thứ mà bạn mong đợi, bao gồm:

  • tất cả các thuộc tính font liên quan bao gồm căng và phong cách
  • liên kết văn bản (trái, phải, trung tâm, biện minh)
  • văn bản gói
  • văn bản cắt tỉa
  • trang trí văn bản (dấu gạch dưới, tấn công qua etcetera)

Dưới đây là một ví dụ đơn giản về những gì có thể đạt được với nó:

<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> 

mà kết quả trong:

enter image description here

Dưới đây là đoạn code cho điều khiển:

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

điều này sẽ thật tuyệt vời nếu đột quỵ nằm ngoài các chữ cái. Cám ơn vì đã chia sẻ. – discorax

+2

Khi sử dụng TemplateBinding với thuộc tính Text tôi nhận được một ngoại lệ đối tượng null. Xuất hiện từ chức năng MeasureOverride nơi định dạng văn bản là null –

+1

Tôi đã thêm điều này ngay lập tức sau this.EnsureFormattedText(); trong MeasureOverride –

1

Trong Trộn, bạn có thể chuyển đổi TextBlock thành đường dẫn, sau đó sử dụng các thuộc tính Stroke bình thường. Nhưng tôi giả sử bạn muốn một cái gì đó mà bạn có thể làm cho năng động ...

Nếu không tôi sẽ nghĩ rằng nó sẽ có được một số loại hiệu ứng bitmap hoặc bàn chải đặc biệt.

0

<TextBlock> không có thuộc tính trang trí. Tôi sẽ đặt nó trên <Canvas> với < Hình chữ nhật > và áp dụng đột quỵ ở đó.

+1

@ kaiz.net: Border! HÔN. – user7116

6

bạn nên quấn TextBlock với một Border .. một cái gì đó như thế này:

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

trong cơ hội ra bạn đang yêu cầu làm thế nào để đưa một cơn đột quỵ xung quanh các chữ cái thực tế (và không phải là toàn bộ TextBlock), bạn có thể muốn nhìn vào bằng cách sử dụng một BitmapEffect của Glow và thiết lập các thông số trên Glow là màu stroke bạn muốn, vv Nếu không bạn có thể phải tạo ra một cái gì đó tùy chỉnh.

31

Tìm thấy nó. Không dễ dàng để làm rõ ràng, không có được xây dựng trong văn bản Stroke trong WPF (loại một tính năng thiếu lớn nếu bạn hỏi tôi). Trước tiên, hãy tạo lớp tùy chỉnh:

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

Bạn có thể tham chiếu nó trong xaml của bạn.

<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

Điều này làm việc thực sự tốt cho tôi, nhưng tôi cũng cần gói từ và căn chỉnh văn bản. Điều này có thể dễ dàng thực hiện bằng cách sử dụng các thuộc tính FormattedText.MaxTextWidth và FormattedText.TextAlignment. – Twelve47

+1

Tuyệt vời! Lưu ý rằng IAddChild không còn được dùng nữa. Thay vào đó, hãy gán thuộc tính với [ContentProperty ("Text")], bạn có thể đặt văn bản trực tiếp trong XAML như sau: Văn bản! Skrymsli

+0

Điều này thật tuyệt vời. Vì câu trả lời này hơi cũ một chút, liệu có cách nào khác để đạt được điều này hay đây vẫn là cách tiếp cận tốt nhất? +1 –

2

"How to: Create Outlined Text" on MSDN có tất cả thông tin bạn cần.

+3

-1: câu trả lời chỉ liên kết là không hợp lệ vì có liên kết bị thối. – ANeves

+0

Liên kết không còn hợp lệ. – LawMan

+1

Hãy thử điều này: [link (https://msdn.microsoft.com/en-us/library/vstudio/ms745816 (v = vs.90) .aspx) –

1

Chỉ có thể sử dụng Nhãn thay thế. Nó có nhiều thuộc tính mà bạn có thể chơi cùng. Ví dụ:

<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

Điều này đã giúp tôi rất nhiều! Chỉ trong trường hợp bất cứ ai cần nó trong tương lai, đây là phiên bản VB (làm StrokeThickness một đôi và thêm một tài sản Gạch chân):

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

nhẹ sửa đổi mã Kent Boogaart của đó, trong khi đáng sợ, là mất tích một chi tiết nhỏ . Đây có thể là một chút không chính xác ở chỗ nó sẽ chỉ đo điền và không đột quỵ nhưng thêm một vài dòng để OnRender()Viewbox sẽ có thể có được một xử lý về những gì để làm với nó (mặc dù, như với TextBox, không phải trong xem trước).

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

Tôi đang sử dụng điều này với hai lớp văn bản để nét vẽ chỉ xuất hiện ở bên ngoài như sau. Điều này rõ ràng sẽ không hoạt động ngay vì nó đề cập đến hình ảnh và phông chữ cụ thể.

<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

Tôi đã sử dụng giải pháp của Kent trong kiểm soát tùy chỉnh của mình. Nó dẫn đến một ngoại lệ null khi sử dụng templatebinding đối với thuộc tính văn bản.

tôi đã phải thay đổi chức năng MeasureOverride như vậy:

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

Cần lưu ý rằng tôi đã không kiểm tra kỹ lưỡng này.

0

Tôi cũng đang cố gắng đạt được điều gì đó tương tự như vậy. Các lớp được đề cập ở đây rất tuyệt, nhưng không chính xác những gì tôi đang tìm kiếm, bởi vì nó chỉ thực sự nhìn đúng nếu văn bản đủ lớn. Các văn bản tôi đã cố gắng để hiển thị là khoảng 10-11 kích thước phông chữ, và đột quỵ là quá lớn các loại chữ được pha trộn với nhau.

Chỉ cần làm rõ, văn bản này được cho là phủ lên hình ảnh do người dùng xác định, có thể có các màu khác nhau và tôi muốn đảm bảo văn bản này sẽ hiển thị.

Tôi không biết nếu điều này là thực hành tốt nhất hay không, nhưng điều này ít nhất đạt được kiểu tóc tôi muốn (dựa trên 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> 

Sau đó cho TextBlocks thực tế, tôi kết hợp hai kiểu Outer TextBlocks vì ai quá nhẹ, và một Inner kiểu 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> 

Ngoài ra, bạn có thể sử dụng DropShadowEffect, trông ổn với việc sử dụng chỉ có hai hộp văn bản (mặc dù bổ sung thêm DropShadowEffects với hướng khác nhau và hạ opacit y có thể trông thậm chí còn tốt hơn):

<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

Nếu áp dụng cho bất cứ ai, đây là một giải pháp đơn giản sử dụng CHỈ XAML, Không sureif nó tốt hơn hoặc tồi tệ hơn về hiệu suất, nhưng chắc chắn nó trông tốt hơn sau đó bất kỳ giải pháp khác trên (trong tôi trường hợp). Tôi Warp nó trong ContentContro l Phong cách (và Template), theo gương Trường Cũ này :) 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

tôi đã để thêm video này MeasureOverride vì vậy nó sẽ hiển thị dòng duy nhất của văn bản khi sử dụng bố trí làm tròn. Nó hoạt động tốt khi văn bản được gói mặc dù.

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

tôi sửa đổi câu trả lời đã bỏ phiếu nhất với một số sửa lỗi, bao gồm:

  • Fix để văn bản bằng một dòng duy nhất sẽ hiển thị khi sử dụng UseLayoutRounding.

  • Đường viền sẽ hiển thị bên ngoài văn bản thay vì ở giữa biên giới .

  • Bút chỉ được tạo một lần thay vì trên mỗi kết xuất.

  • Khắc phục để nó không bị đổ vỡ khi văn bản được đặt thành rỗng.

  • Khắc phục đề cương sử dụng các vòng tròn phù hợp.

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

Cảm ơn bạn đã chia sẻ điều này cho biết thêm sự hoàn hảo cho giải pháp trước đó. Tại sao không ai upvoted bạn? – Luca

+0

Tôi đoán câu hỏi là quá cũ, WPF không phải là nóng nữa hoặc kết hợp cả hai? :) –

+1

WPF là HOT! vì vậy chỉ có cơ hội đầu tiên là – Luca

Các vấn đề liên quan