astel-labs.net

C#などのプログラミングTipsや雑記をつらつらと書くかもしれないブログです。

  • Home
RSS

WPF – 文字の縁取りをする

Posted on 2012年5月6日 by Nymphaea
No CommentsLeave a comment

結構前に 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() );
        }
    }
}

 

Categories: C#, WPF, プログラミング

 

WPF – SnippingTool っぽい物を作ってみた
WPF – TextBlockでのURLアドレスの検出とHyperlinkの改行

コメントを残す

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

  • 2012年5月
    日 月 火 水 木 金 土
     12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
    « 4月   7月 »
  • 最近の投稿

    • raspberry pi に nginx をセットアップする
    • VSCode を日本語化する
    • raspberry pi に VSCode をインストールする
    • WindowsのプロダクトIDを取得する
    • SQL Server – money型とdecimal型を併用した金額計算
  • アーカイブ

    • 2020年3月
    • 2016年12月
    • 2014年6月
    • 2014年5月
    • 2013年7月
    • 2012年11月
    • 2012年7月
    • 2012年5月
    • 2012年4月
    • 2011年4月
    • 2011年1月
    • 2010年11月
    • 2010年10月
    • 2010年9月
    • 2010年8月
    • 2010年7月
    • 2010年6月
    • 2010年5月
    • 2010年4月
  • カテゴリー

    • C#
    • jQuery
    • OpenCV
    • raspberry pi
    • SharePoint
    • Silverlight
    • SQL Server
    • WCF
    • WPF
    • プログラミング
    • 未分類
    • 雑記
© astel-labs.net. Proudly Powered by WordPress | Nest Theme by YChong

このブログ内で公開されているソースコードおよびサンプルプログラムに関わるライセンスはすべて修正BSDライセンス(New BSD License)として公開しています。
但し、サンプルプログラムに含まれる外部アセンブリが同様のライセンスとは限りませんので、利用する前に必ずすべてのライセンスの確認を行ってください。