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

■ Control 클래스를 사용해 사용자 지정 가능한 모양을 가진 컨트롤을 만드는 방법을 보여준다.

TestProject.zip
0.01MB

▶ THEME\generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestProject">
    <Style TargetType="{x:Type local:NumericUpDownControl}">
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Setter Property="VerticalAlignment"   Value="Center" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:NumericUpDownControl}">
                    <Grid Margin="3">
                        <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <Border Grid.RowSpan="2"
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Center"
                            Margin="2"
                            BorderThickness="1"
                            BorderBrush="Gray">
                            <TextBlock
                                Width="60"
                                Padding="5"
                                TextAlignment="Right"
                                Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value}" />
                        </Border>
                        <RepeatButton Grid.Row="0" Grid.Column="1"
                            Command="{x:Static local:NumericUpDownControl.IncreaseCommand}">
                            Up
                        </RepeatButton>
                        <RepeatButton Grid.Row="1" Grid.Column="1"
                            Command="{x:Static local:NumericUpDownControl.DecreaseCommand}">
                            Down
                        </RepeatButton>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

 

▶ NumericUpDownControl.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace TestProject
{
    /// <summary>
    /// 숫자 UP/DOWN 컨트롤
    /// </summary>
    public partial class NumericUpDownControl : Control
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Routed Event
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 값 변경시 이벤트 - ValueChangedEvent

        /// <summary>
        /// 값 변경시 이벤트
        /// </summary>
        public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent
        (
            "ValueChanged",
            RoutingStrategy.Bubble,
            typeof(RoutedPropertyChangedEventHandler<decimal>),
            typeof(NumericUpDownControl)
        );

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 값 변경시 이벤트 - ValueChanged

        /// <summary>
        /// 값 변경시 이벤트
        /// </summary>
        public event RoutedPropertyChangedEventHandler<decimal> ValueChanged
        {
            add
            {
                AddHandler(ValueChangedEvent, value);
            }
            remove
            {
                RemoveHandler(ValueChangedEvent, value);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Dependent Property
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 값 속성 - ValueProperty

        /// <summary>
        /// 값 속성
        /// </summary>
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register
        (
            "Value",
            typeof(decimal),
            typeof(NumericUpDownControl),
            new FrameworkPropertyMetadata
            (
                MinimumValue,
                new PropertyChangedCallback(ValuePropertyChangedCallback),
                new CoerceValueCallback(ValuePropertyCoerceValueCallback)
            )
        );

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 증가 명령
        /// </summary>
        private static RoutedCommand _increaseCommand;

        /// <summary>
        /// 감소 명령
        /// </summary>
        private static RoutedCommand _decreaseCommand;

        #endregion

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

        #region Field

        /// <summary>
        /// 최소 값
        /// </summary>
        private const decimal MinimumValue = 0;

        /// <summary>
        /// 최대 값
        /// </summary>
        private const decimal MaximumValue = 100;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 증가 명령 - IncreaseCommand

        /// <summary>
        /// 증가 명령
        /// </summary>
        public static RoutedCommand IncreaseCommand
        {
            get
            {
                return _increaseCommand;
            }
        }

        #endregion
        #region 감소 명령 - DecreaseCommand

        /// <summary>
        /// 감소 명령
        /// </summary>
        public static RoutedCommand DecreaseCommand
        {
            get
            {
                return _decreaseCommand;
            }
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 값 - Value

        /// <summary>
        /// 값
        /// </summary>
        public decimal Value
        {
            get
            {
                return (decimal)GetValue(ValueProperty);
            }
            set
            {
                SetValue(ValueProperty, value);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Static

        #region 생성자 - NumericUpDownControl()

        /// <summary>
        /// 생성자
        /// </summary>
        static NumericUpDownControl()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericUpDownControl), new FrameworkPropertyMetadata(typeof(NumericUpDownControl)));
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - NumericUpDownControl()

        /// <summary>
        /// 생성자
        /// </summary>
        public NumericUpDownControl()
        {
            _increaseCommand = new RoutedCommand("IncreaseCommand", typeof(NumericUpDownControl));
            _decreaseCommand = new RoutedCommand("DecreaseCommand", typeof(NumericUpDownControl));

            CommandManager.RegisterClassCommandBinding(typeof(NumericUpDownControl), new CommandBinding(_increaseCommand, ProcessIncreaseCommand));
            CommandManager.RegisterClassCommandBinding(typeof(NumericUpDownControl), new CommandBinding(_decreaseCommand, ProcessDecreaseCommand));

            CommandManager.RegisterClassInputBinding(typeof(NumericUpDownControl), new InputBinding(_increaseCommand, new KeyGesture(Key.Up  )));
            CommandManager.RegisterClassInputBinding(typeof(NumericUpDownControl), new InputBinding(_decreaseCommand, new KeyGesture(Key.Down)));
        }

        #endregion

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

        #region 값 속성 변경시 콜백 처리하기 - ValuePropertyChangedCallback(d, e)

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

            RoutedPropertyChangedEventArgs<decimal> routedPropertyChangedEventArgs = new RoutedPropertyChangedEventArgs<decimal>
            (
                (decimal)e.OldValue,
                (decimal)e.NewValue,
                ValueChangedEvent
            );

            control.ProcessValueChanged(routedPropertyChangedEventArgs);
        }

        #endregion
        #region 값 속성 값 강제시 처리하기 - ValuePropertyCoerceValueCallback(d, value)

        /// <summary>
        /// 값 속성 값 강제시 처리하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="value">값</param>
        /// <returns>처리 값</returns>
        private static object ValuePropertyCoerceValueCallback(DependencyObject d, object value)
        {
            decimal newValue = (decimal)value;

            newValue = Math.Max(MinimumValue, Math.Min(MaximumValue, newValue));

            return newValue;
        }

        #endregion

        #region 증가 명령 처리하기 - ProcessIncreaseCommand(sender, e)

        /// <summary>
        /// 증가 명령 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private static void ProcessIncreaseCommand(object sender, ExecutedRoutedEventArgs e)
        {
            NumericUpDownControl control = sender as NumericUpDownControl;

            if(control != null)
            {
                control.Increase();
            }
        }

        #endregion
        #region 감소 명령 처리하기 - ProcessDecreaseCommand(sender, e)

        /// <summary>
        /// 감소 명령 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private static void ProcessDecreaseCommand(object sender, ExecutedRoutedEventArgs e)
        {
            NumericUpDownControl control = sender as NumericUpDownControl;

            if(control != null)
            {
                control.Decrease();
            }
        }

        #endregion

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

        #region 값 변경시 처리하기 - ProcessValueChanged(e)

        /// <summary>
        /// 값 변경시 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected virtual void ProcessValueChanged(RoutedPropertyChangedEventArgs<decimal> e)
        {
            RaiseEvent(e);
        }

        #endregion

        #region 증가하기 - Increase()

        /// <summary>
        /// 증가하기
        /// </summary>
        protected virtual void Increase()
        {
            Value++;
        }

        #endregion
        #region 감소하기 - Decrease()

        /// <summary>
        /// 감소하기
        /// </summary>
        protected virtual void Decrease()
        {
            Value--;
        }

        #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="TestProject"
    FontFamily="나눔고딕코딩"
    FontSize="16">
    <Grid>
        <local:NumericUpDownControl />
    </Grid>
</Window>
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요