■ 문자 맵 사용하기

------------------------------------------------------------------------------------------------------------------------


TestProject.zip


SymbolView.xaml

 

 

<Border x:Class="TestProject.SymbolView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="23"

    Height="25"

    RenderTransformOrigin="0.5, 0.5"

    Background="White"

    BorderBrush="Black"

    BorderThickness="0 0 1 1">

    <TextBlock x:Name="charcterTextBlock"

        HorizontalAlignment="Center"

        VerticalAlignment="Center"

        FontSize="17"

        Text="" />

</Border>

 

 

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"

    SizeToContent="WidthAndHeight"

    Title="문자 맵 사용하기"

    FontFamily="나눔고딕코딩"

    FontSize="16"

    ResizeMode="CanMinimize">

    <Grid Margin="10">

        <Grid.RowDefinitions>

            <RowDefinition Height="30" />

            <RowDefinition Height="5" />

            <RowDefinition Height="*" />

            <RowDefinition Height="20" />

            <RowDefinition Height="30" />

        </Grid.RowDefinitions>

        <Grid Grid.Row="0">

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="50" />

                <ColumnDefinition Width="5"   />

                <ColumnDefinition Width="300" />

            </Grid.ColumnDefinitions>

            <TextBlock Grid.Row="0" Grid.Column="0"

                HorizontalAlignment="Center"

                VerticalAlignment="Center">

                폰트

            </TextBlock>

            <ComboBox x:Name="fontComboBox"

                Grid.Row="0"

                Grid.Column="2"

                VerticalAlignment="Center"

                MaxDropDownHeight="200"

                ItemsSource="{x:Static Fonts.SystemFontFamilies}"

                SelectionChanged="fontComboBox_SelectionChanged">

                <ComboBox.ItemsPanel>

                    <ItemsPanelTemplate >

                        <VirtualizingStackPanel />

                    </ItemsPanelTemplate>

                </ComboBox.ItemsPanel>

            </ComboBox>

        </Grid>

        <Grid Grid.Row="2"

            Width="366"

            Height="251"

            Focusable="True">

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="*" />

                <ColumnDefinition Width="20" />

            </Grid.ColumnDefinitions>

            <ScrollBar x:Name="scrollBar"

                Grid.Column="1"

                ViewportSize="1"

                Minimum="0"

                Maximum="0"

                Scroll="scrollBar_Scroll" />

            <Border

                BorderBrush="Black"

                BorderThickness="1"

                PreviewMouseLeftButtonDown="border_PreviewMouseLeftButtonDown"

                MouseWheel="border_MouseWheel">

                <Canvas x:Name="canvas" />

            </Border>

        </Grid>

        <Grid

            Grid.Row="4">

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="110" />

                <ColumnDefinition Width="5"   />

                <ColumnDefinition Width="100" />

                <ColumnDefinition Width="5"   />

                <ColumnDefinition Width="80" />

                <ColumnDefinition Width="5"   />

                <ColumnDefinition Width="80" />

            </Grid.ColumnDefinitions>

            <TextBlock

                Grid.Column="0">

                복사할 문자들

            </TextBlock>

            <RichTextBox x:Name="richTextBox" Grid.Column="2"

                VerticalContentAlignment="Bottom" />

            <Button Grid.Column="4"

                Click="selectButton_Click">

                선택

            </Button>

            <Button Grid.Column="6"

                Click="copyButton_Click">

                복사

            </Button>

        </Grid>

    </Grid>

</Window>

 

 

MainWindow.xaml.cs

 

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Controls.Primitives;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Threading;

 

namespace TestProject

{

    /// <summary>

    /// 메인 윈도우

    /// </summary>

    public partial class MainWindow : Window

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

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

 

        #region Field

 

        /// <summary>

        /// 스케일 변환

        /// </summary>

        private ScaleTransform scaleTransform = new ScaleTransform(2, 2);

 

        /// <summary>

        /// 이전 기호 뷰

        /// </summary>

        private SymbolView previousSymbolView = null;

 

        /// <summary>

        /// Z 인덱스

        /// </summary>

        private int zIndex;

 

        /// <summary>

        /// 디스패처 타이머

        /// </summary>

        private DispatcherTimer dispatcherTimer;

 

        /// <summary>

        /// 현재 인덱스

        /// </summary>

        private int currentIndex = -1;

 

        /// <summary>

        /// 기호 서체

        /// </summary>

        private GlyphTypeface glyphTypeface;

 

        /// <summary>

        /// 문자 맵 사전

        /// </summary>

        private IDictionary<int, ushort> characterMapDictionary;

 

        /// <summary>

        /// 인덱스

        /// </summary>

        private int index = 0;

 

        /// <summary>

        /// 항목 인덱스

        /// </summary>

        private int itemIndex = 0;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - MainWindow()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainWindow()

        {

            InitializeComponent();

 

            Loaded += Window_Loaded;

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        //////////////////////////////////////////////////////////////////////////////// Function

 

        #region 프리뷰 키 하강시 처리하기 - OnPreviewKeyDown(e)

 

        /// <summary>

        /// 프리뷰 키 하강시 처리하기

        /// </summary>

        /// <param name="e">이벤트 인자</param>

        protected override void OnPreviewKeyDown(KeyEventArgs e)

        {

            if(this.currentIndex != -1)

            {

                if(e.Key == Key.Right)

                {

                    SymbolView symbolView = null;

 

                    if(this.currentIndex != 149)

                    {

                        symbolView = this.canvas.Children[++this.currentIndex] as SymbolView;

                    }

                    else

                    {

                        if(this.scrollBar.Value != this.scrollBar.Maximum)

                        {

                            this.scrollBar.Value += 0.1d;

 

                            Repaint(this.scrollBar.Value);

 

                            symbolView = this.canvas.Children[this.currentIndex - 14] as SymbolView;

                        }

                    }

 

                    if(symbolView != null)

                    {

                        ResetPreviousSymbol();

 

                        FocusSymbolView(symbolView);

                    }

                }

                else if(e.Key == Key.Left)

                {

                    SymbolView symbolView = null;

 

                    if(this.currentIndex != 0)

                    {

                        symbolView = this.canvas.Children[--this.currentIndex] as SymbolView;

                    }

                    else

                    {

                        if(this.scrollBar.Value != 0)

                        {

                            this.scrollBar.Value -= 0.1d;

 

                            Repaint(this.scrollBar.Value);

 

                            symbolView = this.canvas.Children[this.currentIndex + 14] as SymbolView;

                        }

                    }

 

                    if(symbolView != null)

                    {

                        ResetPreviousSymbol();

 

                        FocusSymbolView(symbolView);

                    }

                }

                else if(e.Key == Key.Down)

                {

                    SymbolView symbolView = null;

 

                    if((this.currentIndex + 15) < 150)

                    {

                        symbolView = this.canvas.Children[this.currentIndex + 15] as SymbolView;

                    }

                    else

                    {

                        if(this.scrollBar.Value != this.scrollBar.Maximum)

                        {

                            this.scrollBar.Value += 0.1d;

 

                            Repaint(this.scrollBar.Value);

 

                            symbolView = this.canvas.Children[this.currentIndex] as SymbolView;

                        }

                    }

 

                    if(symbolView != null)

                    {

                        ResetPreviousSymbol();

 

                        FocusSymbolView(symbolView);

                    }

                }

                else if(e.Key == Key.Up)

                {

                    SymbolView symbolView = null;

 

                    if((this.currentIndex - 15) > 0)

                    {

                        symbolView = this.canvas.Children[this.currentIndex - 15] as SymbolView;

                    }

                    else

                    {

                        if(this.scrollBar.Value != 0)

                        {

                            this.scrollBar.Value -= 0.1d;

 

                            Repaint(scrollBar.Value);

 

                            symbolView = this.canvas.Children[this.currentIndex] as SymbolView;

                        }

                    }

 

                    if(symbolView != null)

                    {

                        ResetPreviousSymbol();

 

                        FocusSymbolView(symbolView);

                    }

                }

            }

 

            base.OnKeyDown(e);

        }

 

        #endregion

 

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

        //////////////////////////////////////////////////////////////////////////////// Event

 

        #region 윈도우 로드시 처리하기 - Window_Loaded(sender, e)

 

        /// <summary>

        /// 윈도우 로드시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void Window_Loaded(object sender, RoutedEventArgs e)

        {

            double left = 0d;

            double top  = 0d;

 

            while(true)

            {

                SymbolView symbolView = new SymbolView();

 

                Canvas.SetLeft(symbolView, left);

                Canvas.SetTop (symbolView, top);

 

                this.canvas.Children.Add(symbolView);

 

                left += 23d;

 

                if(left >= 345d)

                {

                    left = 0d;

 

                    top += 25d;

                }

 

                if(top >= 250d)

                {

                    break;

                }

            }

 

            this.fontComboBox.SelectedIndex = 0;

 

            Extract();

        }

 

        #endregion

        #region 폰트 콤보 박스 선택 변경시 처리하기 - fontComboBox_SelectionChanged(sender, e)

 

        /// <summary>

        /// 폰트 콤보 박스 선택 변경시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void fontComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)

        {

            Extract();

        }

 

        #endregion

        #region 스크롤 바 스크롤시 처리하기 - scrollBar_Scroll(sender, e)

 

        /// <summary>

        /// 스크롤 바 스크롤시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void scrollBar_Scroll(object sender, ScrollEventArgs e)

        {

            Repaint(e.NewValue);

        }

 

        #endregion

        #region 경계선 프리뷰 마우스 왼쪽 버튼 하강시 처리하기 - border_PreviewMouseLeftButtonDown(sender, e)

 

        /// <summary>

        /// 경계선 프리뷰 마우스 왼쪽 버튼 하강시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void border_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            SymbolView symbolView = null;

 

            if(e.OriginalSource is SymbolView)

            {

                symbolView = e.OriginalSource as SymbolView;

            }

            else

            {

                FrameworkElement frameworkElement = e.OriginalSource as FrameworkElement;

 

                if(frameworkElement != null)

                {

                    symbolView = frameworkElement.Parent as SymbolView;

                }

            }

 

            if(symbolView != null)

            {

                ResetPreviousSymbol();

 

                FocusSymbolView(symbolView);

            }

        }

 

        #endregion

        #region 경계선 마우스 휠 처리하기 - border_MouseWheel(sender, e)

 

        /// <summary>

        /// 경계선 마우스 휠 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void border_MouseWheel(object sender, MouseWheelEventArgs e)

        {

            this.scrollBar.Value += -(e.Delta * 0.01d);

 

            Repaint(this.scrollBar.Value);

        }

 

        #endregion

        #region 선택 버튼 클릭시 처리하기 - selectButton_Click(sender, e)

 

        /// <summary>

        /// 선택 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void selectButton_Click(object sender, RoutedEventArgs e)

        {

            if(this.currentIndex != -1)

            {

                this.richTextBox.BeginChange();

 

                if(this.richTextBox.Selection.Text != string.Empty)

                {

                    this.richTextBox.Selection.Text = string.Empty;

                }

 

                this.richTextBox.CaretPosition.Paragraph.Inlines.Add

                (

                    new Run

                    (

                        ((SymbolView)canvas.Children[this.currentIndex]).charcterTextBlock.Text

                    )

                    {

                        FontFamily = this.fontComboBox.SelectedItem as FontFamily

                    }

                );

 

                this.richTextBox.EndChange();

            }

        }

 

        #endregion

        #region 복사 버튼 클릭시 처리하기 - copyButton_Click(sender, e)

 

        /// <summary>

        /// 복사 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void copyButton_Click(object sender, RoutedEventArgs e)

        {

            Clipboard.SetData(DataFormats.UnicodeText, this.richTextBox.Selection.Text);

        }

 

        #endregion

        #region 디스패처 타이머 틱 발생시 처리하기 - dispatcherTimer_Tick(sender, e)

 

        /// <summary>

        /// 디스패처 타이머 틱 발생시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void dispatcherTimer_Tick(object sender, EventArgs e)

        {

            try

            {

                SymbolView symbolView = this.canvas.Children[this.itemIndex] as SymbolView;

 

                int index = this.characterMapDictionary.Keys.ElementAt(this.index);

 

                char character = Convert.ToChar(index);

 

                symbolView.charcterTextBlock.Text = character.ToString();

 

                this.itemIndex++;

 

                this.index++;

            }

            catch

            {

                SymbolView symbolView = this.canvas.Children[this.itemIndex] as SymbolView;

 

                symbolView.charcterTextBlock.Text = string.Empty;

 

                this.itemIndex++;

 

                this.index++;

            }

 

            if(this.itemIndex >= 150)

            {

                this.dispatcherTimer.Stop();

 

                this.itemIndex = 0;

            }

        }

 

        #endregion

    

        //////////////////////////////////////////////////////////////////////////////// Function

 

        #region 추출하기 - Extract()

 

        /// <summary>

        /// 추출하기

        /// </summary>

        private void Extract()

        {

            if(canvas != null)

            {

                this.scrollBar.Value = 0;

 

                this.index = 0;

 

                if(this.previousSymbolView != null)

                {

                    this.previousSymbolView.RenderTransform = null;

                    this.previousSymbolView.BorderThickness = new Thickness(0, 0, 1, 1);

 

                    Canvas.SetZIndex(this.previousSymbolView, this.zIndex);

                }

 

                this.currentIndex = -1;

 

                TextElement.SetFontFamily(this.canvas, this.fontComboBox.SelectedItem as FontFamily);

 

                Dispatcher.BeginInvoke

                (

                    DispatcherPriority.Background,

                    new Action

                    (

                        () =>

                        {

                            FontFamily fontFamily = this.fontComboBox.SelectedItem as FontFamily;

 

                            foreach(Typeface typeface in fontFamily.GetTypefaces())

                            {

                                typeface.TryGetGlyphTypeface(out this.glyphTypeface);

 

                                if(this.glyphTypeface != null)

                                {

                                    this.characterMapDictionary = this.glyphTypeface.CharacterToGlyphMap;

 

                                    if(this.dispatcherTimer == null)

                                    {

                                        this.dispatcherTimer = new DispatcherTimer();

 

                                        this.dispatcherTimer.Interval = TimeSpan.FromMilliseconds(0.01);

 

                                        this.dispatcherTimer.Tick -= this.dispatcherTimer_Tick;

                                        this.dispatcherTimer.Tick += this.dispatcherTimer_Tick;

                                    }

 

                                    this.index = 0;

 

                                    this.dispatcherTimer.Start();

 

                                    break;

                                }

                                else

                                {

                                    continue;

                                }

                            }

 

                            this.scrollBar.Maximum = ((this.characterMapDictionary.Values.Count / 15) * 0.1) - 0.9;

                        }

                    )

                );

            }

        }

 

        #endregion

        #region 다시 칠하기 - Repaint(scrollValue)

 

        /// <summary>

        /// 다시 칠하기

        /// </summary>

        /// <param name="scrollValue">스크롤 값</param>

        private void Repaint(double scrollValue)

        {

            this.index = Convert.ToInt32((scrollValue / 0.1) * 15);

 

            this.itemIndex = 0;

 

            this.dispatcherTimer.Start();

        }

 

        #endregion

        #region 이전 기호 재설정하기 - ResetPreviousSymbol()

 

        /// <summary>

        /// 이전 기호 재설정하기

        /// </summary>

        private void ResetPreviousSymbol()

        {

            if(this.previousSymbolView != null)

            {

                this.previousSymbolView.RenderTransform = null;

                this.previousSymbolView.BorderThickness = new Thickness(0, 0, 1, 1);

 

                Canvas.SetZIndex(this.previousSymbolView, this.zIndex);

            }

        }

 

        #endregion

        #region 기호 뷰 포커스 설정하기 - FocusSymbolView(symbolView)

 

        /// <summary>

        /// 기호 뷰 포커스 설정하기

        /// </summary>

        /// <param name="symbolView">기호 뷰</param>

        private void FocusSymbolView(SymbolView symbolView)

        {

            this.currentIndex = canvas.Children.IndexOf(symbolView);

 

            symbolView.RenderTransform = this.scaleTransform;

            symbolView.BorderThickness = new Thickness(1, 1, 2, 2);

 

            this.zIndex = Canvas.GetZIndex(symbolView);

 

            Canvas.SetZIndex(symbolView, 150);

 

            this.previousSymbolView = symbolView;

        }

 

        #endregion

    }

}

 

------------------------------------------------------------------------------------------------------------------------

Posted by 사용자 icodebroker