첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

■ EventManager 클래스 : RegisterRoutedEvent 정적 메소드를 사용해 라우팅 이벤트 만들기

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


TestProject.zip


KnockButton.cs

 

 

using System;

using System.Globalization;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Input;

using System.Windows.Media;

 

namespace TestProject

{

    /// <summary>

    /// 노크 버튼

    /// </summary>

    public class KnockButton : Control

    {

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

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

 

        #region 노크 이벤트 - Knock

 

        /// <summary>

        /// 노크 이벤트

        /// </summary>

        public event RoutedEventHandler Knock

        {

            add

            {

                AddHandler(KnockEvent, value);

            }

            remove

            {

                RemoveHandler(KnockEvent, value);

            }

        }

 

        #endregion

        #region 노크 사전 이벤트 - PreviewKnock

 

        /// <summary>

        /// 노크 사전 이벤트

        /// </summary>

        public event RoutedEventHandler PreviewKnock

        {

            add

            {

                AddHandler(PreviewKnockEvent, value);

            }

            remove

            {

                RemoveHandler(PreviewKnockEvent, value);

            }

        }

 

        #endregion

 

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

        ////////////////////////////////////////////////////////////////////////////////////////// Static

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

 

        #region Field

 

        /// <summary>

        /// 텍스트 속성

        /// </summary>

        public static readonly DependencyProperty TextProperty;

 

        /// <summary>

        /// 노크 이벤트

        /// </summary>

        public static readonly RoutedEvent KnockEvent;

 

        /// <summary>

        /// 노크 사전 이벤트

        /// </summary>

        public static readonly RoutedEvent PreviewKnockEvent;

 

        #endregion

 

        ////////////////////////////////////////////////////////////////////////////////////////// Instance

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

 

        #region Field

 

        /// <summary>

        /// 포맷 텍스트

        /// </summary>

        private FormattedText formattedText;

 

        /// <summary>

        /// 마우스 상위 여부

        /// </summary>

        private bool isMouseReallyOver;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property

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

 

        #region 텍스트 - Text

 

        /// <summary>

        /// 텍스트

        /// </summary>

        public string Text

        {

            set

            {

                SetValue(TextProperty, value == null ? " " : value);

            }

            get

            {

                return (string)GetValue(TextProperty);

            }

        }

 

        #endregion

 

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

        ////////////////////////////////////////////////////////////////////////////////////////// Static

 

        #region 생성자 - KnockButton()

 

        /// <summary>

        /// 생성자

        /// </summary>

        static KnockButton()

        {

            TextProperty = DependencyProperty.Register

            (

                "Text",

                typeof(string),

                typeof(KnockButton),

                new FrameworkPropertyMetadata

                (

                    " ",

                    FrameworkPropertyMetadataOptions.AffectsMeasure

                )

            );

 

 

            KnockEvent = EventManager.RegisterRoutedEvent

            (

                "Knock",

                RoutingStrategy.Bubble,

                typeof(RoutedEventHandler),

                typeof(KnockButton)

            );

 

            PreviewKnockEvent = EventManager.RegisterRoutedEvent

            (

                "PreviewKnock",

                RoutingStrategy.Tunnel,

                typeof(RoutedEventHandler),

                typeof(KnockButton)

            );

        }

 

        #endregion

 

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

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

 

        #region 노크시 처리하기 - OnKnock()

 

        /// <summary>

        /// 노크시 처리하기

        /// </summary>

        protected virtual void OnKnock()

        {

            RoutedEventArgs e = new RoutedEventArgs();

 

            e.RoutedEvent = KnockButton.KnockEvent;

            e.Source      = this;

 

            RaiseEvent(e);

        }

 

        #endregion

        #region 프리뷰 노크시 처리하기 - OnPreviewKnock()

 

        /// <summary>

        /// 프리뷰 노크시 처리하기

        /// </summary>

        protected virtual void OnPreviewKnock()

        {

            RoutedEventArgs e = new RoutedEventArgs();

 

            e.RoutedEvent = KnockButton.PreviewKnockEvent;

            e.Source      = this;

 

            RaiseEvent(e);

        }

 

        #endregion

        #region 마우스 진입시 처리하기 - OnMouseEnter(e)

 

        /// <summary>

        /// 마우스 진입시 처리하기

        /// </summary>

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

        protected override void OnMouseEnter(MouseEventArgs e)

        {

            base.OnMouseEnter(e);

 

            InvalidateVisual();

        }

 

        #endregion

        #region 마우스 이탈시 처리하기 - OnMouseLeave(e)

 

        /// <summary>

        /// 마우스 이탈시 처리하기

        /// </summary>

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

        protected override void OnMouseLeave(MouseEventArgs e)

        {

            base.OnMouseLeave(e);

 

            InvalidateVisual();

        }

 

        #endregion

        #region 마우스 이동시 처리하기 - OnMouseMove(e)

 

        /// <summary>

        /// 마우스 이동시 처리하기

        /// </summary>

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

        protected override void OnMouseMove(MouseEventArgs e)

        {

            base.OnMouseMove(e);

 

            Point mousePoint = e.GetPosition(this);

 

            bool isReallyOverNow =

            (

                mousePoint.X >= 0 && mousePoint.X < ActualWidth &&

                mousePoint.Y >= 0 && mousePoint.Y < ActualHeight

            );

 

            if(isReallyOverNow != this.isMouseReallyOver)

            {

                this.isMouseReallyOver = isReallyOverNow;

 

                InvalidateVisual();

            }

        }

 

        #endregion

        #region 마우스 왼쪽 버튼 DOWN 처리하기 - OnMouseLeftButtonDown(e)

 

        /// <summary>

        /// 마우스 왼쪽 버튼 DOWN 처리하기

        /// </summary>

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

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)

        {

            base.OnMouseLeftButtonDown(e);

 

            CaptureMouse();

 

            InvalidateVisual();

 

            e.Handled = true;

        }

 

        #endregion

        #region 마우스 왼쪽 버튼 UP 처리하기 - OnMouseLeftButtonUp(e)

 

        /// <summary>

        /// 마우스 왼쪽 버튼 UP 처리하기

        /// </summary>

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

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)

        {

            base.OnMouseLeftButtonUp(e);

 

            if(IsMouseCaptured)

            {

                if(this.isMouseReallyOver)

                {

                    OnPreviewKnock();

 

                    OnKnock();

                }

 

                e.Handled = true;

 

                Mouse.Capture(null);

            }

        }

 

        #endregion

        #region 마우스 캡처 해제시 처리하기 - OnLostMouseCapture(e)

 

        /// <summary>

        /// 마우스 캡처 해제시 처리하기

        /// </summary>

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

        protected override void OnLostMouseCapture(MouseEventArgs e)

        {

            base.OnLostMouseCapture(e);

 

            InvalidateVisual();

        }

 

        #endregion

        #region 키 DOWN 처리하기 - OnKeyDown(e)

 

        /// <summary>

        /// 키 DOWN 처리하기

        /// </summary>

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

        protected override void OnKeyDown(KeyEventArgs e)

        {

            base.OnKeyDown(e);

 

            if(e.Key == Key.Space || e.Key == Key.Enter)

            {

                e.Handled = true;

            }

        }

 

        #endregion

        #region 키 UP 처리하기 - OnKeyUp(e)

 

        /// <summary>

        /// 키 UP 처리하기

        /// </summary>

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

        protected override void OnKeyUp(KeyEventArgs e)

        {

            base.OnKeyUp(e);

 

            if(e.Key == Key.Space || e.Key == Key.Enter)

            {

                OnPreviewKnock();

 

                OnKnock();

 

                e.Handled = true;

            }

        }

 

        #endregion

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

 

        /// <summary>

        /// 측정하기 (오버라이딩)

        /// </summary>

        /// <param name="availableSize">이용 가능한 크기</param>

        /// <returns>측정 크기</returns>

        protected override Size MeasureOverride(Size availableSize)

        {

            this.formattedText = new FormattedText

            (

                Text,

                CultureInfo.CurrentCulture,

                FlowDirection,

                new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),

                FontSize,

                Foreground

            );

 

            Size desiredSize = new Size(Math.Max(48, this.formattedText.Width) + 4, this.formattedText.Height + 4);

 

            desiredSize.Width  += Padding.Left + Padding.Right;

            desiredSize.Height += Padding.Top  + Padding.Bottom;

 

            desiredSize.Width  = Math.Min(desiredSize.Width , availableSize.Width );

            desiredSize.Height = Math.Min(desiredSize.Height, availableSize.Height);

 

            return desiredSize;

        }

 

        #endregion

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

 

        /// <summary>

        /// 렌더링 처리하기

        /// </summary>

        /// <param name="drawingContext">DrawingContext</param>

        protected override void OnRender(DrawingContext drawingContext)

        {

            Brush backgroundBrush = SystemColors.ControlBrush;

 

            if(this.isMouseReallyOver && IsMouseCaptured)

            {

                backgroundBrush = SystemColors.ControlDarkBrush;

            }

 

            Pen pen = new Pen(Foreground, IsMouseOver ? 2 : 1);

 

            drawingContext.DrawRoundedRectangle

            (

                backgroundBrush,

                pen,

                new Rect(new Point(0, 0), RenderSize),

                4,

                4

            );

 

            this.formattedText.SetForegroundBrush

            (

                IsEnabled ? Foreground : SystemColors.ControlDarkBrush

            );

 

            Point textPoint = new Point(2, 2);

 

            switch(HorizontalContentAlignment)

            {

                case HorizontalAlignment.Left :

 

                    textPoint.X += Padding.Left;

 

                    break;

 

                case HorizontalAlignment.Right :

 

                    textPoint.X += RenderSize.Width - this.formattedText.Width - Padding.Right;

 

                    break;

 

                case HorizontalAlignment.Center  :

                case HorizontalAlignment.Stretch :

 

                    textPoint.X += (RenderSize.Width - this.formattedText.Width - Padding.Left - Padding.Right) / 2;

 

                    break;

            }

 

            switch(VerticalContentAlignment)

            {

                case VerticalAlignment.Top :

 

                    textPoint.Y += Padding.Top;

 

                    break;

 

                case VerticalAlignment.Bottom :

 

                    textPoint.Y += RenderSize.Height - this.formattedText.Height - Padding.Bottom;

 

                    break;

 

                case VerticalAlignment.Center  :

                case VerticalAlignment.Stretch :

 

                    textPoint.Y += (RenderSize.Height - this.formattedText.Height - Padding.Top - Padding.Bottom) / 2;

 

                    break;

            }

 

            drawingContext.DrawText(this.formattedText, textPoint);

        }

 

        #endregion

    }

}

 

 

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="EventManager 클래스 : RegisterRoutedEvent 정적 메소드를 사용해 라우팅 이벤트 만들기"

    FontFamily="나눔고딕코딩"

    FontSize="16">

    <Grid>

        <local:KnockButton x:Name="button"

            HorizontalAlignment="Center"

            VerticalAlignment="Center"

            Width="100"

            Height="30"

            Text="테스트" />

    </Grid>

</Window>

 

 

MainWindow.xaml.cs

 

 

using System.Windows;

 

namespace TestProject

{

    /// <summary>

    /// 메인 윈도우

    /// </summary>

    public partial class MainWindow : Window

    {

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

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

 

        #region 생성자 - MainWindow()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainWindow()

        {

            InitializeComponent();

 

            this.button.PreviewKnock += button_PreviewKnock;

            this.button.Knock        += button_Knock;

        }

 

        #endregion

 

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

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

 

        #region 버튼 프리뷰 노크시 처리하기 - button_PreviewKnock(sender, e)

 

        /// <summary>

        /// 버튼 프리뷰 노크시 처리하기

        /// </summary>

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

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

        private void button_PreviewKnock(object sender, RoutedEventArgs e)

        {

            MessageBox.Show(this, "버튼 프리뷰 노크 이벤트");

        }

 

        #endregion

        #region 버튼 노크시 처리하기 - button_Knock(sender, e)

 

        /// <summary>

        /// 버튼 노크시 처리하기

        /// </summary>

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

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

        private void button_Knock(object sender, RoutedEventArgs e)

        {

            MessageBox.Show(this, "버튼 노크 이벤트");

        }

 

        #endregion

    }

}

 

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

Posted by 사용자 icodebroker
TAG , ,

댓글을 달아 주세요