結構前に 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() ); } } }
コメントを残す
コメントを投稿するにはログインしてください。