Применить обводку к текстовому блоку в WPF - PullRequest
57 голосов
/ 18 сентября 2008

Как применить обводку (контур вокруг текста) к текстовому блоку в xaml в WPF?

Ответы [ 16 ]

1 голос
/ 18 сентября 2008

В Blend вы можете преобразовать TextBlock в Path, а затем использовать обычные свойства Stroke. Но я предполагаю, что вы хотели что-то, что вы могли бы сделать динамическим ...

В противном случае я бы подумал, что это должен быть какой-то растровый эффект или специальная кисть.

0 голосов
/ 11 апреля 2014

Я тоже пытался добиться чего-то похожего на это. Классы, упомянутые здесь, были великолепны, но не совсем то, что я искал, потому что это действительно выглядело правильно, только если текст был достаточно большим. Текст, который я пытался отобразить, имел размер шрифта около 10–11, а обводка была настолько большой, что буквы как бы смешивались вместе.

Просто чтобы уточнить, этот текст должен был быть наложен на пользовательское изображение, которое могло иметь различные цвета, и я хотел убедиться, что этот текст будет отображаться.

Я не знаю, является ли это наилучшей практикой или нет, но это, по крайней мере, позволило мне выглядеть так, как я хотел (на основании этой статьи ):

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

Затем для фактических текстовых блоков я объединил два текстовых блока в внешнем стиле, потому что один был слишком легким, а другой - в текстовом блоке во внутреннем стиле:

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

В качестве альтернативы, вы могли бы использовать DropShadowEffect, который выглядел хорошо, используя только два текстовых поля (хотя добавление большего количества DropShadowEffect с различными направлениями и пониженной непрозрачностью может выглядеть даже лучше):

<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>
0 голосов
/ 18 июля 2012

Я использовал решение Кента в своем пользовательском контроле. Это привело к пустому исключению при использовании привязки шаблона к свойству text.

Мне пришлось изменить функцию MeasureOverride следующим образом:

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

Следует отметить, что я не проверил это полностью.

0 голосов
/ 02 июня 2012

Небольшая модификация кода Кента Бугаарта, которая, хотя и великолепна, но в ней отсутствуют мелкие детали. Это, вероятно, немного неточно, поскольку он будет измерять только заливку, а не обводку, но добавив пару строк к OnRender() Viewbox, можно будет определить, что с ним делать (хотя, как и в случае TextBox, без предварительного просмотра).

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

Я использую это с двумя слоями текста, поэтому обводка выглядит только снаружи, как показано ниже. Это, очевидно, не сработает сразу, так как относится к конкретным изображениям и шрифтам.

<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 голосов
/ 23 июля 2011

Это мне очень помогло! На всякий случай, если кому-то это понадобится в будущем, вот версия VB (сделав StrokeThickness двойным и добавив свойство подчеркивания):

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 голосов
/ 18 сентября 2008

не имеет декоративных атрибутов. Я бы поставил его на с и применил там штрих.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...