結構前に WPF で文字の縁取りについて話題にしたことがありましたが、その後 MSDN のサンプルコードを基に私なりに実装を行って利用していたのですが、つい最近海外のサイトを巡っていた際、スマートな方法で文字の縁取りをしているサンプルコードを見つけたため紹介します
(アクセス解析でも、検索ワードが「縁取り」でこのサイトに来る方が意外と多いようでした)
ちなみに、サンプルを実行すると以下のようになります
文字列表示の xaml コードです
縁取りの太さは StrokeThickness、縁取りの色は Stroke、文字色は Fill で指定します
フォントの情報は Font~ 関連プロパティで指定します
<Window x:Class="OutlineFont.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:OutlineFont"
Title="MainWindow" Height="160" Width="402">
<Grid>
<local:OutlineText FontFamily="Verdana" FontSize="50" FontWeight="ExtraBold" TextWrapping="Wrap"
StrokeThickness="3" Stroke="Red" Fill="Yellow"
Text="Hello world!" />
</Grid>
</Window>
で、文字列縁取り用のコードが以下になります
例によって GW の最終日でいろいろと疲れて眠いため、説明は省略です。。。
using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Markup;
using System.Windows.Media;
namespace OutlineFont
{
[ContentProperty( "Text" )]
internal class OutlineText : FrameworkElement
{
private FormattedText FormattedText;
private Geometry TextGeometry;
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text", typeof( string ), typeof( OutlineText ),
new FrameworkPropertyMetadata( OnFormattedTextInvalidated ) );
public static readonly DependencyProperty TextAlignmentProperty = DependencyProperty.Register(
"TextAlignment", typeof( TextAlignment ), typeof( OutlineText ),
new FrameworkPropertyMetadata( OnFormattedTextUpdated ) );
public static readonly DependencyProperty TextDecorationsProperty = DependencyProperty.Register(
"TextDecorations", typeof( TextDecorationCollection ), typeof( OutlineText ),
new FrameworkPropertyMetadata( OnFormattedTextUpdated ) );
public static readonly DependencyProperty TextTrimmingProperty = DependencyProperty.Register(
"TextTrimming", typeof( TextTrimming ), typeof( OutlineText ),
new FrameworkPropertyMetadata( OnFormattedTextUpdated ) );
public static readonly DependencyProperty TextWrappingProperty = DependencyProperty.Register(
"TextWrapping", typeof( TextWrapping ), typeof( OutlineText ),
new FrameworkPropertyMetadata( TextWrapping.NoWrap, OnFormattedTextUpdated ) );
public static readonly DependencyProperty FillProperty = DependencyProperty.Register(
"Fill", typeof( Brush ), typeof( OutlineText ),
new FrameworkPropertyMetadata( Brushes.Red, FrameworkPropertyMetadataOptions.AffectsRender ) );
public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
"Stroke", typeof( Brush ), typeof( OutlineText ),
new FrameworkPropertyMetadata( Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender ) );
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
"StrokeThickness", typeof( double ), typeof( OutlineText ),
new FrameworkPropertyMetadata( 1d, FrameworkPropertyMetadataOptions.AffectsRender ) );
public static readonly DependencyProperty FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(
typeof( OutlineText ), new FrameworkPropertyMetadata( OnFormattedTextUpdated ) );
public static readonly DependencyProperty FontSizeProperty = TextElement.FontSizeProperty.AddOwner(
typeof( OutlineText ), new FrameworkPropertyMetadata( OnFormattedTextUpdated ) );
public static readonly DependencyProperty FontStretchProperty = TextElement.FontStretchProperty.AddOwner(
typeof( OutlineText ), new FrameworkPropertyMetadata( OnFormattedTextUpdated ) );
public static readonly DependencyProperty FontStyleProperty = TextElement.FontStyleProperty.AddOwner(
typeof( OutlineText ), new FrameworkPropertyMetadata( OnFormattedTextUpdated ) );
public static readonly DependencyProperty FontWeightProperty = TextElement.FontWeightProperty.AddOwner(
typeof( OutlineText ), new FrameworkPropertyMetadata( OnFormattedTextUpdated ) );
public OutlineText()
{
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();
this.FormattedText.MaxTextWidth = Math.Min( 3579139, availableSize.Width );
this.FormattedText.MaxTextHeight = availableSize.Height;
return new Size( this.FormattedText.Width, this.FormattedText.Height );
}
protected override Size ArrangeOverride( Size finalSize )
{
this.EnsureFormattedText();
this.FormattedText.MaxTextWidth = finalSize.Width;
this.FormattedText.MaxTextHeight = finalSize.Height;
this.TextGeometry = null;
return finalSize;
}
private static void OnFormattedTextInvalidated( DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e )
{
var outlinedTextBlock = (OutlineText)dependencyObject;
outlinedTextBlock.FormattedText = null;
outlinedTextBlock.TextGeometry = null;
outlinedTextBlock.InvalidateMeasure();
outlinedTextBlock.InvalidateVisual();
}
private static void OnFormattedTextUpdated( DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e )
{
var outlinedTextBlock = (OutlineText)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() );
}
}
}

コメントを残す
コメントを投稿するにはログインしてください。