첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

TestProject.zip
다운로드

▶ OutlineTextBlock.cs

using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Markup;
using System.Windows.Media;

namespace TestProject
{
    /// <summary>
    /// 외곽선 텍스트 블럭
    /// </summary>
    [ContentProperty("Text")]
    public class OutlineTextBlock : FrameworkElement
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// 채우기 속성
        /// </summary>
        public static readonly DependencyProperty FillProperty = DependencyProperty.Register
        (
            "Fill",
            typeof(Brush),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata
            (
                Brushes.Black,
                FrameworkPropertyMetadataOptions.AffectsRender
            )
        );

        /// <summary>
        /// 스트로크 속성
        /// </summary>
        public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register
        (
            "Stroke",
            typeof(Brush),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata
            (
                Brushes.Black,
                FrameworkPropertyMetadataOptions.AffectsRender
            )
        );

        /// <summary>
        /// 스트로크 두께 속성
        /// </summary>
        public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register
        (
            "StrokeThickness",
            typeof(double),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata
            (
                1d,
                FrameworkPropertyMetadataOptions.AffectsRender
            )
        );

        /// <summary>
        /// 폰트 패밀리 속성
        /// </summary>
        public static readonly DependencyProperty FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner
        (
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(FontPropertyChangedCallback)
        );

        /// <summary>
        /// 폰트 크기 속성
        /// </summary>
        public static readonly DependencyProperty FontSizeProperty = TextElement.FontSizeProperty.AddOwner
        (
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(FontPropertyChangedCallback)
        );

        /// <summary>
        /// 폰트 신축성 속성
        /// </summary>
        public static readonly DependencyProperty FontStretchProperty = TextElement.FontStretchProperty.AddOwner
        (
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(FontPropertyChangedCallback)
        );

        /// <summary>
        /// 폰트 스타일 속성
        /// </summary>
        public static readonly DependencyProperty FontStyleProperty = TextElement.FontStyleProperty.AddOwner
        (
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(FontPropertyChangedCallback)
        );

        /// <summary>
        /// 폰트 가중치 속성
        /// </summary>
        public static readonly DependencyProperty FontWeightProperty = TextElement.FontWeightProperty.AddOwner
        (
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(FontPropertyChangedCallback)
        );

        /// <summary>
        /// 텍스트 속성
        /// </summary>
        public static readonly DependencyProperty TextProperty = DependencyProperty.Register
        (
            "Text",
            typeof(string),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(TextPropertyChangedCallback)
        );

        /// <summary>
        /// 텍스트 정렬 속성
        /// </summary>
        public static readonly DependencyProperty TextAlignmentProperty = DependencyProperty.Register
        (
            "TextAlignment",
            typeof(TextAlignment),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(FontPropertyChangedCallback)
        );

        /// <summary>
        /// 텍스트 장식 속성
        /// </summary>
        public static readonly DependencyProperty TextDecorationsProperty = DependencyProperty.Register
        (
            "TextDecorations",
            typeof(TextDecorationCollection),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(FontPropertyChangedCallback)
        );

        /// <summary>
        /// 텍스트 트리밍 속성
        /// </summary>
        public static readonly DependencyProperty TextTrimmingProperty = DependencyProperty.Register
        (
            "TextTrimming",
            typeof(TextTrimming),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(FontPropertyChangedCallback)
        );

        /// <summary>
        /// 텍스트 랩핑 속성
        /// </summary>
        public static readonly DependencyProperty TextWrappingProperty = DependencyProperty.Register
        (
            "TextWrapping",
            typeof(TextWrapping),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata
            (
                TextWrapping.NoWrap,
                FontPropertyChangedCallback
            )
        );

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 포맷 텍스트
        /// </summary>
        private FormattedText formattedText;

        /// <summary>
        /// 텍스트 기하
        /// </summary>
        private Geometry textGeometry;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 채우기 - Fill

        /// <summary>
        /// 채우기
        /// </summary>
        public Brush Fill
        {
            get
            {
                return (Brush)GetValue(FillProperty);
            }
            set
            {
                SetValue(FillProperty, value);
            }
        }

        #endregion
        #region 폰트 패밀리 - FontFamily

        /// <summary>
        /// 폰트 패밀리
        /// </summary>
        public FontFamily FontFamily
        {
            get
            {
                return (FontFamily)GetValue(FontFamilyProperty);
            }
            set
            {
                SetValue(FontFamilyProperty, value);
            }
        }

        #endregion
        #region 폰트 크기 - FontSize

        /// <summary>
        /// 폰트 크기
        /// </summary>
        [TypeConverter(typeof(FontSizeConverter))]
        public double FontSize
        {
            get
            {
                return (double)GetValue(FontSizeProperty);
            }
            set
            {
                SetValue(FontSizeProperty, value);
            }
        }

        #endregion
        #region 폰트 신축성 - FontStretch

        /// <summary>
        /// 폰트 신축성
        /// </summary>
        public FontStretch FontStretch
        {
            get
            {
                return (FontStretch)GetValue(FontStretchProperty);
            }
            set
            {
                SetValue(FontStretchProperty, value);
            }
        }

        #endregion
        #region 폰트 스타일 - FontStyle

        /// <summary>
        /// 폰트 스타일
        /// </summary>
        public FontStyle FontStyle
        {
            get
            {
                return (FontStyle)GetValue(FontStyleProperty);
            }
            set
            {
                SetValue(FontStyleProperty, value);
            }
        }

        #endregion
        #region 폰트 가중치 - FontWeight

        /// <summary>
        /// 폰트 가중치
        /// </summary>
        public FontWeight FontWeight
        {
            get
            {
                return (FontWeight)GetValue(FontWeightProperty);
            }
            set
            {
                SetValue(FontWeightProperty, value);
            }
        }

        #endregion
        #region 스트로크 - Stroke

        /// <summary>
        /// 스트로크
        /// </summary>
        public Brush Stroke
        {
            get
            {
                return (Brush)GetValue(StrokeProperty);
            }
            set
            {
                SetValue(StrokeProperty, value);
            }
        }

        #endregion
        #region 스트로크 두께 - StrokeThickness

        /// <summary>
        /// 스트로크 두께
        /// </summary>
        public double StrokeThickness
        {
            get
            {
                return (double)GetValue(StrokeThicknessProperty);
            }
            set
            {
                SetValue(StrokeThicknessProperty, value);
            }
        }

        #endregion
        #region 텍스트 - Text

        /// <summary>
        /// 텍스트
        /// </summary>
        public string Text
        {
            get
            {
                return (string)GetValue(TextProperty);
            }
            set
            {
                SetValue(TextProperty, value);
            }
        }

        #endregion
        #region 텍스트 정렬 -TextAlignment

        /// <summary>
        /// 텍스트 정렬
        /// </summary>
        public TextAlignment TextAlignment
        {
            get
            {
                return (TextAlignment)GetValue(TextAlignmentProperty);
            }
            set
            {
                SetValue(TextAlignmentProperty, value);
            }
        }

        #endregion
        #region 텍스트 장식 - TextDecorations

        /// <summary>
        /// 텍스트 장식
        /// </summary>
        public TextDecorationCollection TextDecorations
        {
            get
            {
                return (TextDecorationCollection)this.GetValue(TextDecorationsProperty);
            }
            set
            {
                this.SetValue(TextDecorationsProperty, value);
            }
        }

        #endregion
        #region 텍스트 트리밍 - TextTrimming

        /// <summary>
        /// 텍스트 트리밍
        /// </summary>
        public TextTrimming TextTrimming
        {
            get
            {
                return (TextTrimming)GetValue(TextTrimmingProperty);
            }
            set
            {
                SetValue(TextTrimmingProperty, value);
            }
        }

        #endregion
        #region 텍스트 랩핑 - TextWrapping

        /// <summary>
        /// 텍스트 랩핑
        /// </summary>
        public TextWrapping TextWrapping
        {
            get
            {
                return (TextWrapping)GetValue(TextWrappingProperty);
            }
            set
            {
                SetValue(TextWrappingProperty, value);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - OutlineTextBlock()

        /// <summary>
        /// 생성자
        /// </summary>
        public OutlineTextBlock()
        {
            this.TextDecorations = new TextDecorationCollection();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

        #region 폰트 속성 변경시 콜백 처리하기 - FontPropertyChangedCallback(d, e)

        /// <summary>
        /// 폰트 속성 변경시 콜백 처리하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="e">이벤트 인자</param>
        private static void FontPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            OutlineTextBlock textBlock = d as OutlineTextBlock;

            textBlock.UpdateFormattedText();

            textBlock.textGeometry = null;

            textBlock.InvalidateMeasure();

            textBlock.InvalidateVisual();
        }

        #endregion
        #region 텍스트 속성 변경시 콜백 처리하기 - TextPropertyChangedCallback(d, e)

        /// <summary>
        /// 텍스트 속성 변경시 콜백 처리하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="e">이벤트 인자</param>
        private static void TextPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            OutlineTextBlock textBlock = d as OutlineTextBlock;

            textBlock.formattedText = null;
            textBlock.textGeometry  = null;

            textBlock.InvalidateMeasure();

            textBlock.InvalidateVisual();
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Protected

        #region 렌더시 처리하기 - OnRender(drawingContext)

        /// <summary>
        /// 렌더시 처리하기
        /// </summary>
        /// <param name="drawingContext">드로잉 컨텍스트</param>
        protected override void OnRender(DrawingContext drawingContext)
        {
            SetTextGeometry();

            drawingContext.DrawGeometry(Fill, new Pen(Stroke, StrokeThickness), this.textGeometry);
        }

        #endregion
        #region 측정하기 (오버라이드) - MeasureOverride(availableSize)

        /// <summary>
        /// 측정하기 (오버라이드)
        /// </summary>
        /// <param name="availableSize">이용 가능한 크기</param>
        /// <returns>희망 크기</returns>
        protected override Size MeasureOverride(Size availableSize)
        {
            SetFormattedText();

            this.formattedText.MaxTextWidth  = Math.Min(3579139, availableSize.Width );
            this.formattedText.MaxTextHeight = Math.Max(0.0001d, availableSize.Height);

            return new Size(this.formattedText.Width, this.formattedText.Height);
        }

        #endregion
        #region 정렬하기 (오버라이드) - ArrangeOverride(finalSize)

        /// <summary>
        /// 정렬하기 (오버라이드)
        /// </summary>
        /// <param name="finalSize">최종 크기</param>
        /// <returns>크기</returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            SetFormattedText();

            this.formattedText.MaxTextWidth  = finalSize.Width;
            this.formattedText.MaxTextHeight = finalSize.Height;

            this.textGeometry = null;

            return finalSize;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Private

        #region 포맷 텍스트 업데이트하기 - UpdateFormattedText()

        /// <summary>
        /// 포맷 텍스트 업데이트하기
        /// </summary>
        private void UpdateFormattedText()
        {
            if(this.formattedText == null)
            {
                return;
            }

            this.formattedText.MaxLineCount  = TextWrapping == TextWrapping.NoWrap ? 1 : int.MaxValue;
            this.formattedText.TextAlignment = TextAlignment;
            this.formattedText.Trimming      = TextTrimming;

            this.formattedText.SetFontSize(FontSize);
            this.formattedText.SetFontStyle(FontStyle);
            this.formattedText.SetFontWeight(FontWeight);
            this.formattedText.SetFontFamily(FontFamily);
            this.formattedText.SetFontStretch(FontStretch);
            this.formattedText.SetTextDecorations(TextDecorations);
        }

        #endregion
        #region 포맷 텍스트 설정하기 - SetFormattedText()

        /// <summary>
        /// 포맷 텍스트 설정하기
        /// </summary>
        private void SetFormattedText()
        {
            if(this.formattedText != null || Text == null)
            {
                return;
            }

            this.formattedText = new FormattedText
            (
                Text,
                CultureInfo.CurrentUICulture,
                FlowDirection,
                new Typeface(FontFamily, FontStyle, FontWeight, FontStretches.Normal),
                FontSize,
                Brushes.Black
            );

            UpdateFormattedText();
        }

        #endregion
        #region 텍스트 기하 설정하기 - SetTextGeometry()

        /// <summary>
        /// 텍스트 기하 설정하기
        /// </summary>
        private void SetTextGeometry()
        {
            if(this.textGeometry != null)
            {
                return;
            }

            SetFormattedText();

            this.textGeometry = this.formattedText.BuildGeometry(new Point(0, 0));
        }

        #endregion
    }
}

 

728x90

 

▶ MainWindow.xaml

<Window x:Class="TestProject.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestProject"
    Width="800"
    Height="600"
    Title="외곽선 텍스트 사용하기"
    FontFamily="나눔고딕코딩"
    FontSize="16">
    <Grid>
        <local:OutlineTextBlock x:Name="textOutline"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            StrokeThickness="2"
            Stroke="Orange"
            Fill="Yellow"
            FontSize="48"
            FontWeight="Bold"
            Text="외곽선 텍스트 입니다." />
    </Grid>
</Window>
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요