첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
본 블로그는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 블로그 콘텐츠 향상을 위해 쓰여집니다.

728x90
반응형
728x170

TestProject.zip
다운로드

▶ Enumerations/ValidatingFlag.cs

using System;
using System.ComponentModel;

namespace TestProject
{
    /// <summary>
    /// 검증시 플래그
    /// </summary>
    [Flags]
    public enum ValidatingFlag
    {
        /// <summary>
        /// BEEP_IF_INVALID
        /// </summary>
        BEEP_IF_INVALID = 0x00000001,

        /// <summary>
        /// BEEP_IF_EMPTY
        /// </summary>
        BEEP_IF_EMPTY = 0x00000002,

        /// <summary>
        /// BEEP
        /// </summary>
        BEEP = BEEP_IF_INVALID | BEEP_IF_EMPTY,

        /// <summary>
        /// SET_VALID_IF_INVALID
        /// </summary>
        SET_VALID_IF_INVALID = 0x00000004,

        /// <summary> 
        /// SET_VALID_IF_EMPTY
        /// </summary>
        SET_VALID_IF_EMPTY = 0x00000008,

        /// <summary>
        /// SET_VALID
        /// </summary>
        SET_VALID = SET_VALID_IF_INVALID | SET_VALID_IF_EMPTY,

        /// <summary>
        /// SHOW_MESSAGE_IF_INVALID
        /// </summary>
        SHOW_MESSAGE_IF_INVALID = 0x00000010,

        /// <summary>
        /// SHOW_MESSAGE_IF_EMPTY
        /// </summary>
        SHOW_MESSAGE_IF_EMPTY = 0x00000020,

        /// <summary>
        /// SHOW_MESSAGE
        /// </summary>
        SHOW_MESSAGE = SHOW_MESSAGE_IF_INVALID | SHOW_MESSAGE_IF_EMPTY,

        /// <summary>
        /// SHOW_ICON_IF_INVALID
        /// </summary>
        SHOW_ICON_IF_INVALID = 0x00000040,

        /// <summary>
        /// SHOW_ICON_IF_EMPTY
        /// </summary>
        SHOW_ICON_IF_EMPTY = 0x00000080,

        /// <summary>
        /// SHOW_ICON
        /// </summary>
        SHOW_ICON = SHOW_ICON_IF_INVALID | SHOW_ICON_IF_EMPTY,

        /// <summary>
        /// MAXIMUM_IF_INVALID
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Never)]
        MAXIMUM_IF_INVALID = BEEP_IF_INVALID | SET_VALID_IF_INVALID | SHOW_MESSAGE_IF_INVALID | SHOW_ICON_IF_INVALID,

        /// <summary>
        /// MAXIMUM_IF_EMPTY
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Never)]
        MAXIMUM_IF_EMPTY = BEEP_IF_EMPTY | SET_VALID_IF_EMPTY | SHOW_MESSAGE_IF_EMPTY | SHOW_ICON_IF_EMPTY,

        /// <summary>
        /// MAXIMUM
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Never)]
        MAXIMUM = MAXIMUM_IF_INVALID + MAXIMUM_IF_EMPTY
    };
}

 

▶ Selection.cs

using System;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 선택
    /// </summary>
    public class Selection
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Event
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 텍스트 변경전 이벤트 - TextChanging

        /// <summary>
        /// 텍스트 변경전 이벤트
        /// </summary>
        public event EventHandler TextChanging;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 텍스트 박스 베이스
        /// </summary>
        private TextBoxBase textBoxBase;

        #endregion

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

        #region 텍스트 박스 - TextBox

        /// <summary>
        /// 텍스트 박스
        /// </summary>
        public TextBoxBase TextBox
        {
            get
            {
                return this.textBoxBase;
            }
        }

        #endregion
        #region 시작 인덱스 - StartIndex

        /// <summary>
        /// 시작 인덱스
        /// </summary>
        public int StartIndex
        {
            get
            {
                return this.textBoxBase.SelectionStart;
            }
            set
            {
                this.textBoxBase.SelectionStart = value;
            }
        }

        #endregion
        #region 종료 인덱스 - EndIndex

        /// <summary>
        /// 종료 인덱스
        /// </summary>
        public int EndIndex
        {
            get
            {
                return this.textBoxBase.SelectionStart + this.textBoxBase.SelectionLength;
            }
            set
            {
                this.textBoxBase.SelectionLength = value - this.textBoxBase.SelectionStart;
            }
        }

        #endregion
        #region 길이 - Length

        /// <summary>
        /// 길이
        /// </summary>
        public int Length
        {
            get
            {
                return this.textBoxBase.SelectionLength;
            }
            set
            {
                this.textBoxBase.SelectionLength = value;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Consturctor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - Selection(textBoxBase)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        public Selection(TextBoxBase textBoxBase)
        {
            this.textBoxBase = textBoxBase;
        }

        #endregion
        #region 생성자 - Selection(textBox, startIndex, endIndex)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        /// <param name="startIndex">시작 인덱스</param>
        /// <param name="endIndex">종료 인덱스</param>
        public Selection(TextBoxBase textBoxBase, int startIndex, int endIndex)
        {
            this.textBoxBase = textBoxBase;

            SetSelection(startIndex, endIndex);
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region + 연산자 재정의하기 - +(selection, offset)

        /// <summary>
        /// + 연산자 재정의하기
        /// </summary>
        /// <param name="selection">선택</param>
        /// <param name="offset">오프셋</param>
        /// <returns>선택</returns>
        public static Selection operator +(Selection selection, int offset)
        {
            return new Selection(selection.textBoxBase, selection.StartIndex + offset, selection.EndIndex + offset);
        }

        #endregion

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

        #region 선택 설정하기 - SetSelection(startIndex, endIndex)

        /// <summary>
        /// 선택 설정하기
        /// </summary>
        /// <param name="startIndex">시작 인덱스</param>
        /// <param name="endIndex">종료 인덱스</param>
        public void SetSelection(int startIndex, int endIndex)
        {
            this.textBoxBase.SelectionStart  = startIndex;
            this.textBoxBase.SelectionLength = endIndex - startIndex;
        }

        #endregion
        #region 선택 구하기 - GetSelection(startIndex, endIndex)

        /// <summary>
        /// 선택 구하기
        /// </summary>
        /// <param name="startIndex">시작 인덱스</param>
        /// <param name="endIndex">종료 인덱스</param>
        public void GetSelection(out int startIndex, out int endIndex)
        {
            startIndex = this.textBoxBase.SelectionStart;
            endIndex   = startIndex + this.textBoxBase.SelectionLength;

            if(startIndex < 0)
            {
                startIndex = 0;
            }

            if(endIndex < startIndex)
            {
                endIndex = startIndex;
            }
        }

        #endregion
        #region 대체하기 - Replace(text)

        /// <summary>
        /// 대체하기
        /// </summary>
        /// <param name="text">텍스트</param>
        public void Replace(string text)
        {
            TextChanging?.Invoke(this, null);

            this.textBoxBase.SelectedText = text;
        }

        #endregion
        #region 선택 대체하기 - ReplaceSelection(startIndex, endIndex, text)

        /// <summary>
        /// 선택 대체하기
        /// </summary>
        /// <param name="startIndex">시작 인덱스</param>
        /// <param name="endIndex">종료 인덱스</param>
        /// <param name="text">텍스트</param>
        public void ReplaceSelection(int startIndex, int endIndex, string text)
        {
            SetSelection(startIndex, endIndex);

            Replace(text);
        }

        #endregion
        #region 이동하기 - MoveBy(startOffset, endOffset)

        /// <summary>
        /// 이동하기
        /// </summary>
        /// <param name="startOffset">시작 오프셋</param>
        /// <param name="endOffset">종료 오프셋</param>
        public void MoveBy(int startOffset, int endOffset)
        {
            EndIndex   += endOffset;
            StartIndex += startOffset;
        }

        #endregion
        #region 이동하기 - MoveBy(offset)

        /// <summary>
        /// 이동하기
        /// </summary>
        /// <param name="offset">오프셋</param>
        public void MoveBy(int offset)
        {
            MoveBy(offset, offset);
        }

        #endregion
    }
}

 

▶ SelectionSaver.cs

using System;
using System.Diagnostics;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 선택 저장자
    /// </summary>
    public class SelectionSaver : IDisposable
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 텍스트 박스 베이스
        /// </summary>
        private TextBoxBase textBoxBase;

        /// <summary>
        /// 선택
        /// </summary>
        private Selection selection;

        /// <summary>
        /// 시작 인덱스
        /// </summary>
        private int startIndex;
        
        /// <summary>
        /// 종료 인덱스
        /// </summary>
        private int endIndex;

        #endregion

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

        #region 텍스트 박스 - TextBox

        /// <summary>
        /// 텍스트 박스
        /// </summary>
        public TextBoxBase TextBox
        {
            get
            {
                return this.textBoxBase;
            }
        }

        #endregion
        #region 시작 인덱스 - StartIndex

        /// <summary>
        /// 시작 인덱스
        /// </summary>
        public int StartIndex
        {
            get
            {
                return this.startIndex;
            }
            set
            {
                this.startIndex = value;
            }
        }

        #endregion
        #region 종료 인덱스 - EndIndex

        /// <summary>
        /// 종료 인덱스
        /// </summary>
        public int EndIndex
        {
            get
            {
                return this.endIndex;
            }
            set
            {
                this.endIndex = value;
            }
        }

        #endregion

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

        #region 생성자 - SelectionSaver(textBoxBase)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        public SelectionSaver(TextBoxBase textBoxBase)
        {
            this.textBoxBase = textBoxBase;

            this.selection = new Selection(textBoxBase);

            this.selection.GetSelection(out this.startIndex, out this.endIndex);
        }

        #endregion
        #region 생성자 - SelectionSaver(textBoxBase, startIndex, endIndex)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        /// <param name="startIndex">시작 인덱스</param>
        /// <param name="endIndex">종료 인덱스</param>
        public SelectionSaver(TextBoxBase textBoxBase, int startIndex, int endIndex)
        {
            this.textBoxBase = textBoxBase;

            this.selection = new Selection(textBoxBase);

            Debug.Assert(startIndex <= endIndex);

            this.startIndex = startIndex;
            this.endIndex   = endIndex;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region + 연산자 재정의하기 - +(saver, offset)

        /// <summary>
        /// + 연산자 재정의하기
        /// </summary>
        /// <param name="saver">선택 저장자</param>
        /// <param name="offset">오프셋</param>
        /// <returns>선택 저장자</returns>
        public static SelectionSaver operator +(SelectionSaver saver, int offset)
        {
            return new SelectionSaver(saver.textBoxBase, saver.startIndex + offset, saver.endIndex + offset);
        }

        #endregion

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

        #region 복구하기 - Restore()

        /// <summary>
        /// 복구하기
        /// </summary>
        public void Restore()
        {
            if(this.textBoxBase == null)
            {
                return;
            }

            this.selection.SetSelection(this.startIndex, this.endIndex);

            this.textBoxBase = null;
        }

        #endregion
        #region 이동하기 - MoveTo(startIndex, endIndex)

        /// <summary>
        /// 이동하기
        /// </summary>
        /// <param name="startIndex">시작 인덱스</param>
        /// <param name="endIndex">종료 인덱스</param>
        public void MoveTo(int startIndex, int endIndex)
        {
            Debug.Assert(startIndex <= endIndex);

            this.startIndex = startIndex;
            this.endIndex   = endIndex;
        }

        #endregion
        #region 이동하기 - MoveBy(startOffset, endOffset)

        /// <summary>
        /// 이동하기
        /// </summary>
        /// <param name="startOffset">시작 오프셋</param>
        /// <param name="endOffset">종료 오프셋</param>
        public void MoveBy(int startOffset, int endOffset)
        {
            this.startIndex += startOffset;
            this.endIndex   += endOffset;

            Debug.Assert(this.startIndex <= this.endIndex);
        }

        #endregion
        #region 이동하기 - MoveBy(offset)

        /// <summary>
        /// 이동하기
        /// </summary>
        /// <param name="offset">오프셋</param>
        public void MoveBy(int offset)
        {
            this.startIndex += offset;
            this.endIndex   += offset;
        }

        #endregion
        #region 갱신하기 - Update()

        /// <summary>
        /// 갱신하기
        /// </summary>
        public void Update()
        {
            if(this.textBoxBase != null)
            {
                this.selection.GetSelection(out this.startIndex, out this.endIndex);
            }
        }

        #endregion
        #region 비활성화하기 - Disable()

        /// <summary>
        /// 비활성화하기
        /// </summary>
        public void Disable()
        {
            this.textBoxBase = null;
        }

        #endregion
        #region 리소스 해제하기 - Dispose()

        /// <summary>
        /// 리소스 해제하기
        /// </summary>
        public void Dispose()
        {
            Restore();
        }

        #endregion
    }
}

 

▶ Behaviors/Behavior.cs

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 동작
    /// </summary>
    public abstract class Behavior : IDisposable
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Import
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Protected

        #region 메시지 비프 처리하기 - MessageBeep(messageBoxIcon)

        /// <summary>
        /// 메시지 비프 처리하기
        /// </summary>
        /// <param name="messageBoxIcon">메시지 박스 아이콘</param>
        /// <returns>처리 결과</returns>
        [DllImport("user32.dll")]
        protected static extern bool MessageBeep(MessageBoxIcon messageBoxIcon);

        #endregion

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

        #region Field

        /// <summary>
        /// 에러 제목
        /// </summary>
        private static string _errorCaption;

        #endregion

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

        #region Field

        /// <summary>
        /// 텍스트 박스 베이스
        /// </summary>
        protected TextBoxBase textBoxBase;

        /// <summary>
        /// 플래그
        /// </summary>
        protected int flags;

        /// <summary>
        /// 텍스트 비변경 여부
        /// </summary>
        protected bool noTextChanged;

        /// <summary>
        /// 선택
        /// </summary>
        protected Selection selection;

        /// <summary>
        /// 에러 제공자
        /// </summary>
        protected ErrorProvider errorProvider;

        #endregion

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

        #region 에러 제목 - ErrorCaption

        /// <summary>
        /// 에러 제목
        /// </summary>
        public static string ErrorCaption
        {
            get
            {
                if(_errorCaption == null)
                {
                    return Application.ProductName;
                }

                return _errorCaption;
            }
            set
            {
                _errorCaption = value;
            }
        }

        #endregion

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

        #region 텍스트 박스 - TextBox

        /// <summary>
        /// 텍스트 박스
        /// </summary>
        public TextBoxBase TextBox
        {
            get
            {
                return this.textBoxBase;
            }
            set
            {
                if(value == null)
                {
                    throw new ArgumentNullException("value");
                }

                RemoveEventHandlers();

                this.textBoxBase = value;

                this.selection = new Selection(this.textBoxBase);

                this.selection.TextChanging += selection_TextChanging;

                AddEventHandlers();
            }
        }

        #endregion
        #region 플래그 - Flags

        /// <summary>
        /// 플래그
        /// </summary>
        public virtual int Flags
        {
            get
            {
                return this.flags;
            }
            set
            {
                if(this.flags == value)
                {
                    return;
                }

                this.flags = value;

                UpdateText();
            }
        }

        #endregion
        #region 에러 메시지 - ErrorMessage

        /// <summary>
        /// 에러 메시지
        /// </summary>
        public virtual string ErrorMessage
        {
            get
            {
                return "Please specify a valid value.";
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        #region 생성자 - Behavior(textBoxBase, addEventHandlers)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        /// <param name="addEventHandlers">이벤트 핸들러 추가 여부</param>
        protected Behavior(TextBoxBase textBoxBase, bool addEventHandlers)
        {
            if(textBoxBase == null)
            {
                throw new ArgumentNullException("textBoxBase");
            }

            this.textBoxBase = textBoxBase;

            this.selection = new Selection(this.textBoxBase);

            this.selection.TextChanging += selection_TextChanging;

            if(addEventHandlers)
            {
                AddEventHandlers();
            }
        }

        #endregion
        #region 생성자 - Behavior(behavior)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="behavior">동작</param>
        protected Behavior(Behavior behavior)
        {
            if(behavior == null)
            {
                throw new ArgumentNullException("behavior");
            }

            TextBox = behavior.TextBox;

            this.flags = behavior.flags;

            behavior.Dispose();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public
        //////////////////////////////////////////////////////////////////////////////// Function

        #region 에러 아이콘 표시하기 - ShowErrorIcon(message)

        /// <summary>
        /// 에러 아이콘 표시하기
        /// </summary>
        /// <param name="message">메시지</param>
        public virtual void ShowErrorIcon(string message)
        {
            if(this.errorProvider == null)
            {
                if(message == string.Empty)
                {
                    return;
                }

                this.errorProvider = new ErrorProvider();
            }

            this.errorProvider.SetError(this.textBoxBase, message);
        }

        #endregion
        #region 에러 메시지 박스 표시하기 - ShowErrorMessageBox(message)

        /// <summary>
        /// 에러 메시지 박스 표시하기
        /// </summary>
        /// <param name="message">메시지</param>
        public virtual void ShowErrorMessageBox(string message)
        {
            MessageBox.Show(this.textBoxBase, message, ErrorCaption, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }

        #endregion
        #region 유효성 여부 구하기 - IsValid()

        /// <summary>
        /// 유효성 여부 구하기
        /// </summary>
        /// <returns>유효성 여부</returns>
        public virtual bool IsValid()
        {
            return true;
        }

        #endregion
        #region 검증하기 - Validate()

        /// <summary>
        /// 검증하기
        /// </summary>
        /// <returns>검증 결과</returns>
        public bool Validate()
        {
            return Validate(Flags, false);
        }

        #endregion
        #region 검증하기 - Validate(flags, setFocusIfNotValid)

        /// <summary>
        /// 검증하기
        /// </summary>
        /// <param name="flags">플래그</param>
        /// <param name="setFocusIfNotValid">무효시 포커스 설정 여부</param>
        /// <returns>검증 결과</returns>
        public virtual bool Validate(int flags, bool setFocusIfNotValid)
        {
            ShowErrorIcon(string.Empty);

            if((flags & (int)ValidatingFlag.MAXIMUM) == 0)
            {
                return true;
            }

            if((flags & (int)ValidatingFlag.MAXIMUM_IF_EMPTY) != 0 && this.textBoxBase.Text == string.Empty)
            {
                if((flags & (int)ValidatingFlag.BEEP_IF_EMPTY) != 0)
                {
                    MessageBeep(MessageBoxIcon.Exclamation);
                }

                if((flags & (int)ValidatingFlag.SET_VALID_IF_EMPTY) != 0)
                {
                    UpdateText();

                    return true;
                }

                if((flags & (int)ValidatingFlag.SHOW_ICON_IF_EMPTY) != 0)
                {
                    ShowErrorIcon(ErrorMessage);
                }

                if((flags & (int)ValidatingFlag.SHOW_MESSAGE_IF_EMPTY) != 0)
                {
                    ShowErrorMessageBox(ErrorMessage);
                }

                if(setFocusIfNotValid)
                {
                    this.textBoxBase.Focus();
                }

                return false;
            }

            if((flags & (int)ValidatingFlag.MAXIMUM_IF_INVALID) != 0 && this.textBoxBase.Text != string.Empty && !IsValid())
            {
                if((flags & (int)ValidatingFlag.BEEP_IF_INVALID) != 0)
                {
                    MessageBeep(MessageBoxIcon.Exclamation);
                }

                if((flags & (int)ValidatingFlag.SET_VALID_IF_INVALID) != 0)
                {
                    UpdateText();

                    return true;
                }

                if((flags & (int)ValidatingFlag.SHOW_ICON_IF_INVALID) != 0)
                {
                    ShowErrorIcon(ErrorMessage);
                }

                if((flags & (int)ValidatingFlag.SHOW_MESSAGE_IF_INVALID) != 0)
                {
                    ShowErrorMessageBox(ErrorMessage);
                }

                if(setFocusIfNotValid)
                {
                    this.textBoxBase.Focus();
                }

                return false;
            }

            return true;
        }

        #endregion
        #region 플래그 수정하기 - ModifyFlags(flags, added)

        /// <summary>
        /// 플래그 수정하기
        /// </summary>
        /// <param name="flags">플래그</param>
        /// <param name="added">추가 여부</param>
        public void ModifyFlags(int flags, bool added)
        {
            if(added)
            {
                Flags = this.flags | flags;
            }
            else
            {
                Flags = this.flags & ~flags;
            }
        }

        #endregion
        #region 플래그 존재 여부 구하기 - HasFlag(flag)

        /// <summary>
        /// 플래그 존재 여부 구하기
        /// </summary>
        /// <param name="flag">플래그</param>
        /// <returns>플래그 존재 여부</returns>
        public bool HasFlag(int flag)
        {
            return (this.flags & flag) != 0;
        }

        #endregion
        #region 텍스트 갱신하기 - UpdateText()

        /// <summary>
        /// 텍스트 갱신하기
        /// </summary>
        /// <returns>처리 결과</returns>
        public virtual bool UpdateText()
        {
            string validText = GetValidText();

            if(validText != this.textBoxBase.Text)
            {
                this.textBoxBase.Text = validText;

                return true;
            }

            return false;
        }

        #endregion
        #region 라인 추적하기 - TraceLine(message)

        /// <summary>
        /// 라인 추적하기
        /// </summary>
        /// <param name="message">메시지</param>
        [Conditional("TRACE_PROJECT")]
        public void TraceLine(string message)
        {
            Trace.WriteLine(message);
        }

        #endregion
        #region 리소스 해제하기 - Dispose()

        /// <summary>
        /// 리소스 해제하기
        /// </summary>
        public virtual void Dispose()
        {
            RemoveEventHandlers();

            this.textBoxBase = null;
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Protected
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 바인딩 포맷시 처리하기 - binding_Format(sender, e)

        /// <summary>
        /// 바인딩 포맷시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected virtual void binding_Format(object sender, ConvertEventArgs e)
        {
        }

        #endregion
        #region 바인딩 파싱시 처리하기 - binding_Parse(sender, e)

        /// <summary>
        /// 바인딩 파싱시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected virtual void binding_Parse(object sender, ConvertEventArgs e)
        {
            if(e.Value.ToString() == string.Empty)
            {
                e.Value = DBNull.Value;
            }
        }

        #endregion
        #region 텍스트 박스 베이스 키 DOWN 처리하기 - textBoxBase_KeyDown(sender, e)

        /// <summary>
        /// 텍스트 박스 베이스 키 DOWN 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected virtual void textBoxBase_KeyDown(object sender, KeyEventArgs e)
        {
            TraceLine("Behavior.textBoxBase_KeyDown " + e.KeyCode);

            e.Handled = false;
        }

        #endregion
        #region 텍스트 박스 베이스 키 PRESS 처리하기 - textBoxBase_KeyPress(sender, e)

        /// <summary>
        /// 텍스트 박스 베이스 키 PRESS 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected virtual void textBoxBase_KeyPress(object sender, KeyPressEventArgs e)
        {
            TraceLine("Behavior.textBoxBase_KeyPress " + e.KeyChar);

            e.Handled = false;
        }

        #endregion
        #region 텍스트 박스 베이스 텍스트 변경시 처리하기 - textBoxBase_TextChanged(sender, e)

        /// <summary>
        /// 텍스트 박스 베이스 텍스트 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected virtual void textBoxBase_TextChanged(object sender, EventArgs e)
        {
            TraceLine("Behavior.textBoxBase_TextChanged " + this.noTextChanged);

            if(!this.noTextChanged)
            {
                UpdateText();
            }

            this.noTextChanged = false;
        }

        #endregion
        #region 텍스트 박스 베이스 검증시 처리하기 - textBoxBase_Validating(sender, e)

        /// <summary>
        /// 텍스트 박스 베이스 검증시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected virtual void textBoxBase_Validating(object sender, CancelEventArgs e)
        {
            TraceLine("Behavior.textBoxBase_Validating");

            e.Cancel = !Validate();
        }

        #endregion
        #region 텍스트 박스 베이스 포커스 상실시 처리하기 - textBoxBase_LostFocus(sender, e)

        /// <summary>
        /// 텍스트 박스 베이스 포커스 상실시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected virtual void textBoxBase_LostFocus(object sender, EventArgs e)
        {
            TraceLine("Behavior.textBoxBase_LostFocus");
        }

        #endregion
        #region 텍스트 박스 베이스 데이터 바인딩 컬렉션 변경시 처리하기 - textBoxBase_DataBindings_CollectionChanged(sender, e)

        /// <summary>
        /// 텍스트 박스 베이스 데이터 바인딩 컬렉션 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected virtual void textBoxBase_DataBindings_CollectionChanged(object sender, CollectionChangeEventArgs e)
        {
            if(e.Action == CollectionChangeAction.Add)
            {
                Binding binding = (Binding)e.Element;

                binding.Format += binding_Format;
                binding.Parse  += binding_Parse;
            }
        }

        #endregion

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

        #region 이벤트 핸들러 추가하기 - AddEventHandlers()

        /// <summary>
        /// 이벤트 핸들러 추가하기
        /// </summary>
        protected virtual void AddEventHandlers()
        {
            this.textBoxBase.KeyDown                        += textBoxBase_KeyDown;
            this.textBoxBase.KeyPress                       += textBoxBase_KeyPress;
            this.textBoxBase.TextChanged                    += textBoxBase_TextChanged;
            this.textBoxBase.Validating                     += textBoxBase_Validating;
            this.textBoxBase.LostFocus                      += textBoxBase_LostFocus;
            this.textBoxBase.DataBindings.CollectionChanged += textBoxBase_DataBindings_CollectionChanged;
        }

        #endregion
        #region 이벤트 핸들러 제거하기 - RemoveEventHandlers()

        /// <summary>
        /// 이벤트 핸들러 제거하기
        /// </summary>
        protected virtual void RemoveEventHandlers()
        {
            if(this.textBoxBase == null)
            {
                return;
            }

            this.textBoxBase.KeyDown                        -= textBoxBase_KeyDown;
            this.textBoxBase.KeyPress                       -= textBoxBase_KeyPress;
            this.textBoxBase.TextChanged                    -= textBoxBase_TextChanged;
            this.textBoxBase.Validating                     -= textBoxBase_Validating;
            this.textBoxBase.LostFocus                      -= textBoxBase_LostFocus;
            this.textBoxBase.DataBindings.CollectionChanged -= textBoxBase_DataBindings_CollectionChanged;
        }

        #endregion
        #region 유효한 텍스트 구하기 - GetValidText()

        /// <summary>
        /// 유효한 텍스트 구하기
        /// </summary>
        /// <returns>유효한 텍스트</returns>
        protected virtual string GetValidText()
        {
            return this.textBoxBase.Text;
        }

        #endregion
        #region 정수 구하기 - ToInt(text)

        /// <summary>
        /// 정수 구하기
        /// </summary>
        /// <param name="text">텍스트</param>
        /// <returns>정수</returns>
        protected int ToInt(string text)
        {
            try
            {
                for(int i = 0, length = text.Length; i < length; i++)
                {
                    if(!Char.IsDigit(text[i]))
                    {
                        return Convert.ToInt32(text.Substring(0, i));
                    }
                }

                return Convert.ToInt32(text);
            }
            catch
            {
                return 0;
            }
        }

        #endregion
        #region 실수 구하기 - ToDouble(text)

        /// <summary>
        /// 실수 구하기
        /// </summary>
        /// <param name="text">텍스트</param>
        /// <returns>실수</returns>
        protected double ToDouble(string text)
        {
            try
            {
                return Convert.ToDouble(text);
            }
            catch
            {
                return 0;
            }
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 선택 텍스트 변경전 처리하기 - selection_TextChanging(sender, e)

        /// <summary>
        /// 선택 텍스트 변경전 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void selection_TextChanging(object sender, EventArgs e)
        {
            this.noTextChanged = true;
        }

        #endregion
    }
}

 

▶ Behaviors/NumericBehavior.cs

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 숫자 동작
    /// </summary>
    public class NumericBehavior : Behavior
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Enumeration
        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        #region 플래그 - Flag

        /// <summary>
        /// 플래그
        /// </summary>
        [Flags]
        protected enum Flag
        {
            /// <summary>
            /// CAN_NOT_BE_NEGATIVE
            /// </summary>
            CAN_NOT_BE_NEGATIVE = 0x00010000,

            /// <summary>
            /// ADD_DECIMAL_AFTER_MAXIMUM_WHOLE_DIGITS
            /// </summary>
            ADD_DECIMAL_AFTER_MAXIMUM_WHOLE_DIGITS = 0x00020000
        };

        #endregion
        #region 포커스 상실시 플래그 - LostFocusFlag

        /// <summary>
        /// 포커스 상실시 플래그
        /// </summary>
        [Flags]
        public enum LostFocusFlag
        {
            /// <summary>
            /// PAD_WITH_ZEROS_BEFORE_DECIMAL
            /// </summary>
            PAD_WITH_ZEROS_BEFORE_DECIMAL = 0x00000100,

            /// <summary>
            /// PAD_WITH_ZEROS_AFTER_DECIMAL
            /// </summary>
            PAD_WITH_ZEROS_AFTER_DECIMAL = 0x00000200,

            /// <summary>
            /// DONT_PAD_WITH_ZEROS_IF_EMPTY
            /// </summary>
            DONT_PAD_WITH_ZEROS_IF_EMPTY = 0x00000400,

            /// <summary>
            /// REMOVE_EXTRA_LEADING_ZEROS
            /// </summary>
            REMOVE_EXTRA_LEADING_ZEROS = 0x00000800,

            /// <summary>
            /// MAXIMUM
            /// </summary>
            [EditorBrowsable(EditorBrowsableState.Never)]
            MAXIMUM = 0x00000F00,

            /// <summary>
            /// CALL_HANDLER_WHEN_TEXT_PROPERTY_IS_SET
            /// </summary>
            CALL_HANDLER_WHEN_TEXT_PROPERTY_IS_SET = 0x00001000,

            /// <summary>
            /// CALL_HANDLER_WHEN_TEXT_CHANGED
            /// </summary>
            CALL_HANDLER_WHEN_TEXT_CHANGED = 0x00002000
        };

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 최대 전체 숫자 카운트
        /// </summary>
        private int maximumWholeDigitCount = 9;

        /// <summary>
        /// 최대 소수점 이하 자리 카운트
        /// </summary>
        private int maximumDecimalPlaceCount = 4;

        /// <summary>
        /// 그룹 내 숫자 카운트
        /// </summary>
        private int digitCountInGroup = 0;

        /// <summary>
        /// 음수 기호
        /// </summary>
        private char negativeSign = NumberFormatInfo.CurrentInfo.NegativeSign[0];

        /// <summary>
        /// 소수점
        /// </summary>
        private char decimalPoint = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator[0];

        /// <summary>
        /// 그룹 분리자
        /// </summary>
        private char groupSeparator = NumberFormatInfo.CurrentInfo.NumberGroupSeparator[0];

        /// <summary>
        /// 접두사
        /// </summary>
        private string prefix = string.Empty;

        /// <summary>
        /// 범위 최소값
        /// </summary>
        private double rangeMinimumValue = double.MinValue;

        /// <summary>
        /// 범위 최대값
        /// </summary>
        private double rangeMaximumValue = double.MaxValue;

        /// <summary>
        /// 이전 분리자 카운트
        /// </summary>
        private int previousSeparatorCount = -1;

        /// <summary>
        /// 키 스트로크에 의한 텍스트 변경 여부
        /// </summary>
        private bool textChangedByKeystroke = false;

        #endregion

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

        #region 에러 메시지 - ErrorMessage

        /// <summary>
        /// 에러 메시지
        /// </summary>
        public override string ErrorMessage
        {
            get
            {
                if(this.rangeMinimumValue > double.MinValue && this.rangeMaximumValue < double.MaxValue)
                {
                    return "Please specify a numeric value between " +
                           this.rangeMinimumValue.ToString()         +
                           " and "                                   +
                           this.rangeMaximumValue.ToString() + ".";
                }
                else if(this.rangeMinimumValue > double.MinValue)
                {
                    return "Please specify a numeric value greater than or equal to " + this.rangeMinimumValue.ToString() + ".";
                }
                else if(this.rangeMaximumValue < double.MinValue)
                {
                    return "Please specify a numeric value less than or equal to " + this.rangeMaximumValue.ToString() + ".";
                }

                return "Please specify a valid numeric value.";
            }
        }

        #endregion
        #region 최대 전체 숫자 카운트 - MaximumWholeDigitCount

        /// <summary>
        /// 최대 전체 숫자 카운트
        /// </summary>
        public int MaximumWholeDigitCount
        {
            get
            {
                return this.maximumWholeDigitCount;
            }
            set
            {
                if(this.maximumWholeDigitCount == value)
                {
                    return;
                }

                this.maximumWholeDigitCount = value;

                if(this.maximumWholeDigitCount < 1)
                {
                    this.maximumWholeDigitCount = 1;
                }

                UpdateText();
            }
        }

        #endregion
        #region 최대 소수점 이하 자리 카운트 - MaximumDecimalPlaceCount

        /// <summary>
        /// 최대 소수점 이하 자리 카운트
        /// </summary>
        public int MaximumDecimalPlaceCount
        {
            get
            {
                return this.maximumDecimalPlaceCount;
            }
            set
            {
                if(this.maximumDecimalPlaceCount == value)
                {
                    return;
                }

                this.maximumDecimalPlaceCount = value;

                if(this.maximumDecimalPlaceCount < 0)
                {
                    this.maximumDecimalPlaceCount = 0;
                }

                UpdateText();
            }
        }

        #endregion
        #region 음수 허용 여부 - AllowNegative

        /// <summary>
        /// 음수 허용 여부
        /// </summary>
        public bool AllowNegative
        {
            get
            {
                return !HasFlag((int)Flag.CAN_NOT_BE_NEGATIVE);
            }
            set
            {
                ModifyFlags((int)Flag.CAN_NOT_BE_NEGATIVE, !value);
            }
        }

        #endregion
        #region 최대 전체 숫자 카운트 설정 후 소수점 추가 여부 - AddDecimalAfterMaximumWholeDigitCount

        /// <summary>
        /// 최대 전체 숫자 카운트 설정 후 소수점 추가 여부
        /// </summary>
        public bool AddDecimalAfterMaximumWholeDigitCount
        {
            get
            {
                return HasFlag((int)Flag.ADD_DECIMAL_AFTER_MAXIMUM_WHOLE_DIGITS);
            }
            set
            {
                ModifyFlags((int)Flag.ADD_DECIMAL_AFTER_MAXIMUM_WHOLE_DIGITS, value);
            }
        }

        #endregion
        #region 그룹 내 숫자 카운트 - DigitCountInGroup

        /// <summary>
        /// 그룹 내 숫자 카운트
        /// </summary>
        public int DigitCountInGroup
        {
            get
            {
                return this.digitCountInGroup;
            }
            set
            {
                if(this.digitCountInGroup == value)
                {
                    return;
                }

                this.digitCountInGroup = value;

                if(this.digitCountInGroup < 0)
                {
                    this.digitCountInGroup = 0;
                }

                UpdateText();
            }
        }

        #endregion
        #region 소수점 - DecimalPoint

        /// <summary>
        /// 소수점
        /// </summary>
        public char DecimalPoint
        {
            get
            {
                return this.decimalPoint;
            }
            set
            {
                if(this.decimalPoint == value)
                {
                    return;
                }

                this.decimalPoint = value;

                AdjustDecimalAndGroupSeparators();

                UpdateText();
            }
        }

        #endregion
        #region 그룹 분리자 - GroupSeparator

        /// <summary>
        /// 그룹 분리자
        /// </summary>
        public char GroupSeparator
        {
            get
            {
                return this.groupSeparator;
            }
            set
            {
                if(this.groupSeparator == value)
                {
                    return;
                }

                this.groupSeparator = value;

                AdjustDecimalAndGroupSeparators();

                UpdateText();
            }
        }

        #endregion
        #region 음수 기호 - NegativeSign

        /// <summary>
        /// 음수 기호
        /// </summary>
        public char NegativeSign
        {
            get
            {
                return this.negativeSign;
            }
            set
            {
                if(this.negativeSign == value)
                {
                    return;
                }

                this.negativeSign = value;

                UpdateText();
            }
        }

        #endregion
        #region 접두사 - Prefix

        /// <summary>
        /// 접두사
        /// </summary>
        public String Prefix
        {
            get
            {
                return this.prefix;
            }
            set
            {
                if(this.prefix == value)
                {
                    return;
                }

                this.prefix = value;

                UpdateText();
            }
        }

        #endregion
        #region 범위 최소값 - RangeMinimumValue

        /// <summary>
        /// 범위 최소값
        /// </summary>
        public double RangeMinimumValue
        {
            get
            {
                return this.rangeMinimumValue;
            }
            set
            {
                this.rangeMinimumValue = value;
            }
        }

        #endregion
        #region 범위 최대값 - RangeMaximumValue

        /// <summary>
        /// 범위 최대값
        /// </summary>
        public double RangeMaximumValue
        {
            get
            {
                return this.rangeMaximumValue;
            }
            set
            {
                this.rangeMaximumValue = value;
            }
        }

        #endregion
        #region 마스크 - Mask

        /// <summary>
        /// 마스크
        /// </summary>
        public string Mask
        {
            get
            {
                StringBuilder stringBuilder = new StringBuilder();

                for(int i = 0; i < this.maximumWholeDigitCount; i++)
                {
                    stringBuilder.Append('0');
                }

                if(this.maximumDecimalPlaceCount > 0)
                {
                    stringBuilder.Append(this.decimalPoint);
                }

                for(int i = 0; i < this.maximumDecimalPlaceCount; i++)
                {
                    stringBuilder.Append('0');
                }

                stringBuilder = new StringBuilder(GetSeparatedText(stringBuilder.ToString()));

                for(int i = 0, length = stringBuilder.Length; i < length; i++)
                {
                    if(stringBuilder[i] == '0')
                    {
                        stringBuilder[i] = '#';
                    }
                }

                return stringBuilder.ToString();
            }
            set
            {
                int decimalPosition = -1;
                int length          = value.Length;

                this.maximumWholeDigitCount   = 0;
                this.maximumDecimalPlaceCount = 0;
                this.digitCountInGroup        = 0;
                this.flags                    = (this.flags & (int)~Flag.CAN_NOT_BE_NEGATIVE);
                this.prefix                   = string.Empty;

                for(int i = length - 1; i >= 0; i--)
                {
                    char character = value[i];

                    if(character == '#')
                    {
                        if(decimalPosition >= 0)
                        {
                            this.maximumWholeDigitCount++;
                        }
                        else
                        {
                            this.maximumDecimalPlaceCount++;
                        }
                    }
                    else if((character == '.' || character == this.decimalPoint) && decimalPosition < 0)
                    {
                        decimalPosition = i;

                        this.decimalPoint = character;
                    }
                    else if(character == ',' || character == this.groupSeparator)
                    {
                        if(this.digitCountInGroup == 0)
                        {
                            this.digitCountInGroup = (((decimalPosition >= 0) ? decimalPosition : length) - i) - 1;
                            this.groupSeparator    = character;
                        }
                    }
                    else
                    {
                        this.prefix = value.Substring(0, i + 1);

                        break;
                    }
                }

                if(decimalPosition < 0)
                {
                    this.maximumWholeDigitCount   = this.maximumDecimalPlaceCount;
                    this.maximumDecimalPlaceCount = 0;
                }

                Debug.Assert(this.maximumWholeDigitCount > 0);

                AdjustDecimalAndGroupSeparators();

                UpdateText();
            }
        }

        #endregion
        #region 숫자 텍스트 - NumericText

        /// <summary>
        /// 숫자 텍스트
        /// </summary>
        public string NumericText
        {
            get
            {
                return GetNumericText(this.textBoxBase.Text, false);
            }
        }

        #endregion
        #region 실제 숫자 텍스트 - RealNumericText

        /// <summary>
        /// 실제 숫자 텍스트
        /// </summary>
        public string RealNumericText
        {
            get
            {
                return GetNumericText(this.textBoxBase.Text, true);
            }
        }

        #endregion

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

        #region 생성자 - NumericBehavior(textBoxBase)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        public NumericBehavior(TextBoxBase textBoxBase) : base(textBoxBase, true)
        {
            AdjustDecimalAndGroupSeparators();
        }

        #endregion
        #region 생성자 - NumericBehavior(textBoxBase, mask)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        /// <param name="mask">마스크</param>
        public NumericBehavior(TextBoxBase textBoxBase, string mask) : base(textBoxBase, true)
        {
            Mask = mask;
        }

        #endregion
        #region 생성자 - NumericBehavior(textBoxBase, maximumWholeDigitCount, maximumDecimalPlaceCount)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스</param>
        /// <param name="maximumWholeDigitCount">최대 전체 숫자 카운트</param>
        /// <param name="maximumDecimalPlaceCount">최대 소수점 자리 카운트</param>
        public NumericBehavior(TextBoxBase textBoxBase, int maximumWholeDigitCount, int maximumDecimalPlaceCount) : this(textBoxBase)
        {
            this.maximumWholeDigitCount   = maximumWholeDigitCount;
            this.maximumDecimalPlaceCount = maximumDecimalPlaceCount;

            if(this.maximumWholeDigitCount < 1)
            {
                this.maximumWholeDigitCount = 1;
            }

            if(this.maximumDecimalPlaceCount < 0)
            {
                this.maximumDecimalPlaceCount = 0;
            }
        }

        #endregion
        #region 생성자 - NumericBehavior(behavior)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="behavior">숫자 동작</param>
        public NumericBehavior(NumericBehavior behavior) : base(behavior)
        {
            this.maximumWholeDigitCount   = behavior.maximumWholeDigitCount;
            this.maximumDecimalPlaceCount = behavior.maximumDecimalPlaceCount;
            this.digitCountInGroup        = behavior.digitCountInGroup;
            this.negativeSign             = behavior.negativeSign;
            this.decimalPoint             = behavior.decimalPoint;
            this.groupSeparator           = behavior.groupSeparator;
            this.prefix                   = behavior.prefix;
            this.rangeMinimumValue        = behavior.rangeMinimumValue;
            this.rangeMaximumValue        = behavior.rangeMaximumValue;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public
        //////////////////////////////////////////////////////////////////////////////// Function

        #region 유효성 여부 구하기 - IsValid()

        /// <summary>
        /// 유효성 여부 구하기
        /// </summary>
        /// <returns>유효성 여부</returns>
        public override bool IsValid()
        {
            double value = ToDouble(RealNumericText);

            return (value >= this.rangeMinimumValue && value <= this.rangeMaximumValue);
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Protected
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 바인딩 파싱시 처리하기 - binding_Parse(sender, e)

        /// <summary>
        /// 바인딩 파싱시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected override void binding_Parse(object sender, ConvertEventArgs e)
        {
            if(e.Value.ToString() == string.Empty)
            {
                e.Value = DBNull.Value;
            }
            else
            {
                e.Value = GetNumericText(e.Value.ToString(), false);
            }
        }

        #endregion
        #region 텍스트 박스 베이스 키 DOWN 처리하기 - textBoxBase_KeyDown(sender, e)

        /// <summary>
        /// 텍스트 박스 베이스 키 DOWN 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected override void textBoxBase_KeyDown(object sender, KeyEventArgs e)
        {
            TraceLine("NumericBehavior.textBoxBase_KeyDown " + e.KeyCode);

            if(e.KeyCode == Keys.Delete)
            {
                int startIndex;
                int endIndex;

                this.selection.GetSelection(out startIndex, out endIndex);

                string text  = this.textBoxBase.Text;
                int   length = text.Length;

                int prefixLength = this.prefix.Length;

                if(startIndex < prefixLength && length > prefixLength)
                {
                    if(endIndex != length)
                    {
                        e.Handled = true;
                    }
                    return;
                }

                this.textChangedByKeystroke = true;

                if(startIndex < length && text[startIndex] == this.groupSeparator && startIndex == endIndex)
                {
                    SendKeys.SendWait("{RIGHT}");
                }

                this.previousSeparatorCount = GetGroupSeparatorCount(text);

                if(endIndex == length)
                {
                    SendKeys.Send("{RIGHT}");
                }
            }
        }

        #endregion
        #region 텍스트 박스 베이스 키 PRESS 처리하기 - textBoxBase_KeyPress(sender, e)

        /// <summary>
        /// 텍스트 박스 베이스 키 PRESS 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected override void textBoxBase_KeyPress(object sender, KeyPressEventArgs e)
        {
            TraceLine("NumericBehavior.textBoxBase_KeyPress " + e.KeyChar);

            if(this.textBoxBase.ReadOnly)
            {
                return;
            }

            char character = e.KeyChar;

            e.Handled = true;

            this.textChangedByKeystroke = true;

            int startIndex;
            int endIndex;

            this.selection.GetSelection(out startIndex, out endIndex);

            string text = this.textBoxBase.Text;

            this.previousSeparatorCount = -1;

            string numericText            = NumericText;
            int    decimalPosition        = text.IndexOf(this.decimalPoint);
            int    numericDecimalPosition = numericText.IndexOf(this.decimalPoint);
            int    length                 = text.Length;
            int    numericLength          = numericText.Length;
            int    prefixLength           = this.prefix.Length;
            int    separatorCount         = GetGroupSeparatorCount(text);

            if(startIndex < prefixLength && !Char.IsControl(character))
            {
                char prefixCharacter = this.prefix[startIndex];

                if(prefixCharacter == character)
                {
                    if(length > startIndex)
                    {
                        endIndex = (endIndex == length ? endIndex : (startIndex + 1));

                        this.selection.ReplaceSelection(startIndex, endIndex, character.ToString());
                    }
                    else
                    {
                        base.textBoxBase_KeyPress(sender, e);
                    }
                }
                else if(Char.IsDigit(character) || character == this.negativeSign || character == this.decimalPoint)
                {
                    endIndex = (endIndex == length ? endIndex : prefixLength);

                    this.selection.ReplaceSelection(startIndex, endIndex, this.prefix.Substring(startIndex));

                    textBoxBase_KeyPress(sender, e);
                }

                return;
            }

            if(character == this.negativeSign && AllowNegative)
            {
                if(startIndex == prefixLength)
                {
                    if(numericText != string.Empty && numericText[0] == this.negativeSign)
                    {
                        endIndex = (endIndex == length ? endIndex : (startIndex + 1));

                        this.selection.ReplaceSelection(startIndex, endIndex, this.negativeSign.ToString());

                        return;
                    }
                }
                else
                {
                    if(numericText[0] == this.negativeSign)
                    {
                        this.selection.ReplaceSelection(prefixLength, prefixLength + 1, string.Empty);

                        this.selection.SetSelection(startIndex - 1, endIndex - 1);
                    }
                    else
                    {
                        this.selection.ReplaceSelection(prefixLength, prefixLength, this.negativeSign.ToString());

                        this.selection.SetSelection(startIndex + 1, endIndex + 1);
                    }

                    return;
                }
            }
            else if(character == this.decimalPoint && this.maximumDecimalPlaceCount > 0)
            {
                if(decimalPosition >= 0)
                {
                    if(decimalPosition >= startIndex && decimalPosition < endIndex)
                    {
                        this.previousSeparatorCount = separatorCount;
                    }
                    else
                    {
                        this.selection.SetSelection(decimalPosition + 1, decimalPosition + 1);

                        return;
                    }
                }
                else
                {
                    this.previousSeparatorCount = separatorCount;
                }
            }
            else if(Char.IsDigit(character))
            {
                if(decimalPosition >= 0 && decimalPosition < startIndex)
                {
                    if(numericText.Substring(numericDecimalPosition + 1).Length == this.maximumDecimalPlaceCount)
                    {
                        if(startIndex <= decimalPosition + this.maximumDecimalPlaceCount)
                        {
                            endIndex = (endIndex == length ? endIndex : (startIndex + 1));

                            this.selection.ReplaceSelection(startIndex, endIndex, character.ToString());
                        }

                        return;
                    }
                }
                else
                {
                    bool isNegative = (numericText.Length != 0 && numericText[0] == this.negativeSign);

                    if(startIndex == this.maximumWholeDigitCount + separatorCount + prefixLength + (isNegative ? 1 : 0))
                    {
                        if(AddDecimalAfterMaximumWholeDigitCount && this.maximumDecimalPlaceCount > 0)
                        {
                            endIndex = (endIndex == length ? endIndex : (startIndex + 2));

                            this.selection.ReplaceSelection(startIndex, endIndex, this.decimalPoint.ToString() + character);
                        }

                        return;
                    }

                    if
                    (
                        numericText.Substring
                        (
                            0,
                            numericDecimalPosition >= 0 ? numericDecimalPosition : numericLength
                        ).Length == this.maximumWholeDigitCount + (isNegative ? 1 : 0)
                    )
                    {
                        if(text[startIndex] == this.groupSeparator)
                        {
                            startIndex++;
                        }

                        endIndex = (endIndex == length ? endIndex : (startIndex + 1));

                        this.selection.ReplaceSelection(startIndex, endIndex, character.ToString());

                        return;
                    }

                    this.previousSeparatorCount = separatorCount;
                }
            }
            else if(Char.IsControl(character))
            {
                this.previousSeparatorCount = separatorCount;
            }
            else
            {
                return;
            }

            base.textBoxBase_KeyPress(sender, e);
        }

        #endregion
        #region 텍스트 박스 베이스 텍스트 변경시 처리하기 - textBoxBase_TextChanged(sender, e)

        /// <summary>
        /// 텍스트 박스 베이스 텍스트 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected override void textBoxBase_TextChanged(object sender, EventArgs e)
        {
            TraceLine("NumericBehavior.textBoxBase_TextChanged");

            SelectionSaver selectionSaver = new SelectionSaver(this.textBoxBase);

            bool textChangedByKeystroke = this.textChangedByKeystroke;

            base.textBoxBase_TextChanged(sender, e);

            if(this.previousSeparatorCount >= 0)
            {
                using(selectionSaver)
                {
                    int newSeparatorCount = GetGroupSeparatorCount(this.textBoxBase.Text);

                    if(this.previousSeparatorCount != newSeparatorCount && selectionSaver.StartIndex > this.prefix.Length)
                    {
                        selectionSaver.MoveBy(newSeparatorCount - this.previousSeparatorCount);
                    }
                }
            }

            if
            (
                HasFlag((int)LostFocusFlag.CALL_HANDLER_WHEN_TEXT_CHANGED) ||
                (!textChangedByKeystroke && HasFlag((int)LostFocusFlag.CALL_HANDLER_WHEN_TEXT_PROPERTY_IS_SET))
            )
            {
                textBoxBase_LostFocus(sender, e);
            }

            this.textChangedByKeystroke = false;
        }

        #endregion
        #region 텍스트 박스 베이스 포커스 상실시 처리하기 - textBoxBase_LostFocus(sender, e)

        /// <summary>
        /// 텍스트 박스 베이스 포커스 상실시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected override void textBoxBase_LostFocus(object sender, EventArgs e)
        {
            TraceLine("NumericBehavior.textBoxBase_LostFocus");

            if(!HasFlag((int)LostFocusFlag.MAXIMUM))
            {
                return;
            }

            string originalText = GetNumericText(this.textBoxBase.Text, true);
            string text         = originalText;
            int    length       = text.Length;

            if(HasFlag((int)LostFocusFlag.REMOVE_EXTRA_LEADING_ZEROS) && length > 0)
            {
                bool isNegative = (text[0] == this.negativeSign);

                if(isNegative)
                {
                    text = text.Substring(1);
                }

                text = text.TrimStart('0');

                if(text == string.Empty || text[0] == this.decimalPoint)
                {
                    text = '0' + text;
                }

                if(isNegative)
                {
                    text = this.negativeSign + text;
                }
            }
            else if(length == 0 && HasFlag((int)LostFocusFlag.DONT_PAD_WITH_ZEROS_IF_EMPTY))
            {
                return;
            }

            int decimalPosition          = text.IndexOf('.');
            int maximumDecimalPlaceCount = this.maximumDecimalPlaceCount;
            int maximuWholeDigitCount    = this.maximumWholeDigitCount;

            if(HasFlag((int)LostFocusFlag.PAD_WITH_ZEROS_AFTER_DECIMAL) && maximumDecimalPlaceCount > 0)
            {
                if(decimalPosition < 0)
                {
                    if(length == 0 || text == "-")
                    {
                        text   = "0";
                        length = 1;
                    }

                    text += '.';

                    decimalPosition = length++;
                }

                text = InsertZeros(text, -1, maximumDecimalPlaceCount - (length - decimalPosition - 1));
            }

            if(HasFlag((int)LostFocusFlag.PAD_WITH_ZEROS_BEFORE_DECIMAL) && maximuWholeDigitCount > 0)
            {
                if(decimalPosition < 0)
                {
                    decimalPosition = length;
                }

                if(length > 0 && text[0] == '-')
                {
                    decimalPosition--;
                }

                text = InsertZeros(text, (length > 0 ? (text[0] == '-' ? 1 : 0) : -1), maximuWholeDigitCount - decimalPosition);
            }

            if(text != originalText)
            {
                if(decimalPosition >= 0 && this.decimalPoint != '.')
                {
                    text = text.Replace('.', this.decimalPoint);
                }

                using(SelectionSaver selectionSaver = new SelectionSaver(this.textBoxBase))
                {
                    this.textBoxBase.Text = text;
                }
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Function
        
        #region 십진수 및 그룹 분리자 조정하기 - AdjustDecimalAndGroupSeparators()

        /// <summary>
        /// 십진수 및 그룹 분리자 조정하기
        /// </summary>
        protected void AdjustDecimalAndGroupSeparators()
        {
            if(this.decimalPoint == this.groupSeparator)
            {
                this.groupSeparator = (this.decimalPoint == ',' ? '.' : ',');
            }
        }

        #endregion
        #region 0 삽입하기 - InsertZeros(text, startIndex, count)

        /// <summary>
        /// 0 삽입하기
        /// </summary>
        /// <param name="text">텍스트</param>
        /// <param name="startIndex">숫자 인덱스</param>
        /// <param name="count">카운트</param>
        /// <returns>처리 결과</returns>
        protected string InsertZeros(string text, int startIndex, int count)
        {
            if(startIndex < 0 && count > 0)
            {
                startIndex = text.Length;
            }

            StringBuilder stringBuilder = new StringBuilder(text);

            for(int i = 0; i < count; i++)
            {
                stringBuilder.Insert(startIndex, '0');
            }

            return stringBuilder.ToString();
        }

        #endregion
        #region 범위 내 조정하기 - AdjustWithinRange()

        /// <summary>
        /// 범위 내 조정하기
        /// </summary>
        protected void AdjustWithinRange()
        {
            if(IsValid())
            {
                return;
            }

            if(this.textBoxBase.Text == string.Empty)
            {
                this.textBoxBase.Text = " ";
            }
            else
            {
                UpdateText();
            }

            double value = ToDouble(RealNumericText);

            if(value < this.rangeMinimumValue)
            {
                this.textBoxBase.Text = this.rangeMinimumValue.ToString();
            }
            else if(value > this.rangeMaximumValue)
            {
                this.textBoxBase.Text = this.rangeMaximumValue.ToString();
            }
        }

        #endregion
        #region 숫자 텍스트 구하기 - GetNumericText(text, realNumeric)

        /// <summary>
        /// 숫자 텍스트 구하기
        /// </summary>
        /// <param name="text">텍스트</param>
        /// <param name="realNumeric">실제 숫자 여부</param>
        /// <returns>숫자 텍스트</returns>
        protected string GetNumericText(string text, bool realNumeric)
        {
            StringBuilder stringBuilder = new StringBuilder();

            bool isNegative      = false;
            bool hasDecimalPoint = false;

            foreach(char character in text)
            {
                if(Char.IsDigit(character))
                {
                    stringBuilder.Append(character);
                }
                else if(character == this.negativeSign)
                {
                    isNegative = true;
                }
                else if(character == this.decimalPoint && !hasDecimalPoint)
                {
                    hasDecimalPoint = true;

                    stringBuilder.Append(realNumeric ? '.' : this.decimalPoint);
                }
            }

            if(isNegative)
            {
                stringBuilder.Insert(0, realNumeric ? '-' : this.negativeSign);
            }

            return stringBuilder.ToString();
        }

        #endregion
        #region 분리된 텍스트 구하기 - GetSeparatedText(text)

        /// <summary>
        /// 분리된 텍스트 구하기
        /// </summary>
        /// <param name="text">텍스트</param>
        /// <returns>분리된 텍스트</returns>
        protected string GetSeparatedText(string text)
        {
            string numericText   = GetNumericText(text, false);
            string separatedText = numericText;

            int decimalPosition = numericText.IndexOf(this.decimalPoint);

            if(decimalPosition >= 0)
            {
                separatedText = separatedText.Substring(0, decimalPosition);
            }

            if(this.digitCountInGroup > 0)
            {
                int length = separatedText.Length;

                bool isNegative = (separatedText != string.Empty && separatedText[0] == this.negativeSign);

                for(int i = length - (this.digitCountInGroup + 1); i >= (isNegative ? 1 : 0); i -= this.digitCountInGroup)
                {
                    separatedText = separatedText.Substring(0, i + 1) + this.groupSeparator + separatedText.Substring(i + 1);
                }
            }

            if(separatedText != string.Empty || decimalPosition >= 0)
            {
                separatedText = this.prefix + separatedText;

                if(decimalPosition >= 0)
                {
                    separatedText += numericText.Substring(decimalPosition);
                }
            }

            return separatedText;
        }

        #endregion
        #region 유효한 텍스트 구하기 - GetValidText()

        /// <summary>
        /// 유효한 텍스트 구하기
        /// </summary>
        /// <returns>유효한 텍스트</returns>
        protected override string GetValidText()
        {
            string text         = this.textBoxBase.Text;
            bool   isNegative   = false;
            int    prefixLength = this.prefix.Length;

            StringBuilder stringBuilder = new StringBuilder();

            for(int i = 0, decimalPosition = -1, newLength = 0, length = text.Length; i < length; i++)
            {
                char character = text[i];

                if(character == this.negativeSign && AllowNegative)
                {
                    isNegative = true;
                }

                else if(Char.IsDigit(character))
                {
                    if(decimalPosition < 0 && newLength == this.maximumWholeDigitCount)
                    {
                        continue;
                    }

                    if(decimalPosition >= 0 && newLength > decimalPosition + this.maximumDecimalPlaceCount)
                    {
                        break;
                    }

                    stringBuilder.Append(character);

                    newLength++;
                }
                else if(character == this.decimalPoint && decimalPosition < 0)
                {
                    if(this.maximumDecimalPlaceCount == 0)
                    {
                        break;
                    }

                    stringBuilder.Append(character);

                    decimalPosition = newLength;

                    newLength++;
                }
            }

            if(isNegative)
            {
                stringBuilder.Insert(0, this.negativeSign);
            }

            return GetSeparatedText(stringBuilder.ToString());
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Function

        #region 그룹 분리자 수 구하기 - GetGroupSeparatorCount(text)

        /// <summary>
        /// 그룹 분리자 수 구하기
        /// </summary>
        /// <param name="text">텍스트</param>
        /// <returns>그룹 분리자 수</returns>
        private int GetGroupSeparatorCount(string text)
        {
            int count = 0;

            foreach(char character in text)
            {
                if(character == this.groupSeparator)
                {
                    count++;
                }
            }

            return count;
        }

        #endregion
    }
}

 

▶ Behaviors/IntegerBehavior.cs

using System;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 정수 동작
    /// </summary>
    public class IntegerBehavior : NumericBehavior
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 최대 소수점 자리 카운트 - MaximumDecimalPlaceCount

        /// <summary>
        /// 최대 소수점 자리 카운트
        /// </summary>
        public new int MaximumDecimalPlaceCount
        {
            get
            {
                return base.MaximumDecimalPlaceCount;
            }
        }

        #endregion
        #region 마스크 - Mask

        /// <summary>
        /// 마스크
        /// </summary>
        public new string Mask
        {
            get
            {
                return base.Mask;
            }
            set
            {
                base.Mask = value;

                if(base.MaximumDecimalPlaceCount > 0)
                {
                    base.MaximumDecimalPlaceCount = 0;
                }
            }
        }
        
        #endregion
        
        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - IntegerBehavior(textBoxBase)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        public IntegerBehavior(TextBoxBase textBoxBase) : base(textBoxBase, 9, 0)
        {
            SetDefaultRange();
        }

        #endregion
        #region 생성자 - IntegerBehavior(textBoxBase, maximumWholeDigitCount)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        /// <param name="maximumWholeDigitCount">최대 전체 숫자 카운트</param>
        public IntegerBehavior(TextBoxBase textBoxBase, int maximumWholeDigitCount) : base(textBoxBase, maximumWholeDigitCount, 0)
        {
            SetDefaultRange();
        }

        #endregion
        #region 생성자 - IntegerBehavior(behavior)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="behavior">정수 동작</param>
        public IntegerBehavior(IntegerBehavior behavior) : base(behavior)
        {
            SetDefaultRange();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 디폴트 범위 설정하기 - SetDefaultRange()

        /// <summary>
        /// 디폴트 범위 설정하기
        /// </summary>
        private void SetDefaultRange()
        {
            RangeMinimumValue = Int32.MinValue;
            RangeMaximumValue = Int32.MaxValue;
        }

        #endregion
    }
}

 

▶ Behaviors/CurrencyBehavior.cs

using System.Globalization;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 통화 동작
    /// </summary>
    public class CurrencyBehavior : NumericBehavior
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - CurrencyBehavior(textBoxBase)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        public CurrencyBehavior(TextBoxBase textBoxBase) : base(textBoxBase)
        {
            this.flags |=
            (
                (int)LostFocusFlag.REMOVE_EXTRA_LEADING_ZEROS   |
                (int)LostFocusFlag.PAD_WITH_ZEROS_AFTER_DECIMAL |
                (int)LostFocusFlag.DONT_PAD_WITH_ZEROS_IF_EMPTY |
                (int)LostFocusFlag.CALL_HANDLER_WHEN_TEXT_PROPERTY_IS_SET
            );

            DigitCountInGroup        = NumberFormatInfo.CurrentInfo.CurrencyGroupSizes[0];
            MaximumDecimalPlaceCount = NumberFormatInfo.CurrentInfo.CurrencyDecimalDigits;
            DecimalPoint             = NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator[0];
            GroupSeparator           = NumberFormatInfo.CurrentInfo.CurrencyGroupSeparator[0];

            switch(NumberFormatInfo.CurrentInfo.CurrencyPositivePattern)
            {
                case 0 : Prefix = NumberFormatInfo.CurrentInfo.CurrencySymbol;       break;
                case 2 : Prefix = NumberFormatInfo.CurrentInfo.CurrencySymbol + ' '; break;
            }

            AdjustDecimalAndGroupSeparators();
        }

        #endregion
        #region 생성자 - CurrencyBehavior(behavior)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="behavior">통화 동작</param>
        public CurrencyBehavior(CurrencyBehavior behavior) : base(behavior)
        {
        }

        #endregion
    }
}

 

▶ Behaviors/AlphanumericBehavior.cs

using System;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 영숫자 동작
    /// </summary>
    public class AlphanumericBehavior : Behavior
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 무효한 문자 배열
        /// </summary>
        private char[] invalidCharacterArray = { '%', '\'', '*', '"', '+', '?', '>', '<', ':', '\\' };

        #endregion

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

        #region 무효한 문자 배열 - InvalidCharacterArray

        /// <summary>
        /// 무효한 문자 배열
        /// </summary>
        public char[] InvalidCharacterArray
        {
            get
            {
                return this.invalidCharacterArray;
            }
            set
            {
                if(this.invalidCharacterArray == value)
                {
                    return;
                }

                this.invalidCharacterArray = value;

                UpdateText();
            }
        }

        #endregion

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

        #region 생성자 - AlphanumericBehavior(textBoxBase)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        public AlphanumericBehavior(TextBoxBase textBoxBase) : base(textBoxBase, true)
        {
        }

        #endregion
        #region 생성자 - AlphanumericBehavior(textBoxBase, invalidCharacterArray)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        /// <param name="invalidCharacterArray">무효한 문자 배열</param>
        public AlphanumericBehavior(TextBoxBase textBoxBase, char[] invalidCharacterArray) : base(textBoxBase, true)
        {
            this.invalidCharacterArray = invalidCharacterArray;
        }

        #endregion
        #region 생성자 - AlphanumericBehavior(textBoxBase, invalidCharacterArray)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        /// <param name="invalidCharacterArray">무효한 문자 배열</param>
        public AlphanumericBehavior(TextBoxBase textBoxBase, string invalidCharacterArray) : base(textBoxBase, true)
        {
            this.invalidCharacterArray = invalidCharacterArray.ToCharArray();
        }

        #endregion
        #region 생성자 - AlphanumericBehavior(behavior)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="behavior">영숫자 동작</param>
        public AlphanumericBehavior(AlphanumericBehavior behavior) : base(behavior)
        {
            this.invalidCharacterArray = behavior.invalidCharacterArray;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public
        //////////////////////////////////////////////////////////////////////////////// Function

        #region 유효한 텍스트 구하기 - GetValidText()

        /// <summary>
        /// 유효한 텍스트 구하기
        /// </summary>
        /// <returns>유효한 텍스트</returns>
        protected override string GetValidText()
        {
            string text = this.textBoxBase.Text;

            if(this.invalidCharacterArray != null && text.IndexOfAny(this.invalidCharacterArray) >= 0)
            {
                foreach(char character in this.invalidCharacterArray)
                {
                    if(text.IndexOf(character) >= 0)
                    {
                        text = text.Replace(character.ToString(), string.Empty);
                    }
                }
            }

            if(text.Length > this.textBoxBase.MaxLength)
            {
                text = text.Remove(this.textBoxBase.MaxLength, text.Length - this.textBoxBase.MaxLength);
            }

            return text;
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Protected
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 텍스트 박스 베이스 키 PRESS 처리하기 - textBoxBase_KeyPress(sender, e)

        /// <summary>
        /// 텍스트 박스 베이스 키 PRESS 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected override void textBoxBase_KeyPress(object sender, KeyPressEventArgs e)
        {
            TraceLine("AlphanumericBehavior.textBoxBase_KeyPress " + e.KeyChar);

            if(this.textBoxBase.ReadOnly || this.invalidCharacterArray == null)
            {
                return;
            }

            char character = e.KeyChar;

            e.Handled = true;

            if(Array.IndexOf(this.invalidCharacterArray, character) >= 0)
            {
                MessageBeep(MessageBoxIcon.Exclamation);

                return;
            }

            string text = this.textBoxBase.Text;

            if(text.Length == this.textBoxBase.MaxLength && this.textBoxBase.MaxLength > 0 && !Char.IsControl(character))
            {
                int startIndex;
                int endIndex;

                this.selection.GetSelection(out startIndex, out endIndex);

                if(startIndex < this.textBoxBase.MaxLength)
                {
                    this.selection.ReplaceSelection(startIndex, startIndex + 1, character.ToString());
                }

                return;
            }

            base.textBoxBase_KeyPress(sender, e);
        }

        #endregion
    }
}

 

▶ Behaviors/MaskedBehavior.cs

using System.Collections;
using System.Text;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 마스크 동작
    /// </summary>
    public class MaskedBehavior : Behavior
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Class
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 상징 - Symbol

        /// <summary>
        /// 상징
        /// </summary>
        public class Symbol
        {
            //////////////////////////////////////////////////////////////////////////////////////////////////// Delegate
            ////////////////////////////////////////////////////////////////////////////////////////// Public

            #region 검증자 메소드 - ValidatorMethod(character)

            /// <summary>
            /// 검증자 메소드
            /// </summary>
            /// <param name="character">문자</param>
            /// <returns>검증 결과</returns>
            public delegate bool ValidatorMethod(char character);

            #endregion
            #region 포매터 메소드 - FormatterMethod(character)

            /// <summary>
            /// 포매터 메소드
            /// </summary>
            /// <param name="character">문자</param>
            /// <returns>문자</returns>
            public delegate char FormatterMethod(char character);

            #endregion

            //////////////////////////////////////////////////////////////////////////////////////////////////// Event
            ////////////////////////////////////////////////////////////////////////////////////////// Public

            #region 검증자 이벤트 - Validator

            /// <summary>
            /// 검증자 이벤트
            /// </summary>
            public event ValidatorMethod Validator;

            #endregion
            #region 포매터 이벤트 - Formatter

            /// <summary>
            /// 포매터 이벤트
            /// </summary>
            public event FormatterMethod Formatter;

            #endregion

            //////////////////////////////////////////////////////////////////////////////////////////////////// Field
            ////////////////////////////////////////////////////////////////////////////////////////// Private

            #region Field

            /// <summary>
            /// 상징
            /// </summary>
            private char symbol;

            #endregion

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

            #region 문자 - Character

            /// <summary>
            /// 문자
            /// </summary>
            public char Character
            {
                get
                {
                    return this.symbol;
                }
                set
                {
                    this.symbol = value;
                }
            }

            #endregion

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

            #region 생성자 - Symbol(symbol, validator, formatter)

            /// <summary>
            /// 생성자
            /// </summary>
            /// <param name="symbol">상징</param>
            /// <param name="validator">검증자</param>
            /// <param name="formatter">포매터</param>
            public Symbol(char symbol, ValidatorMethod validator, FormatterMethod formatter)
            {
                this.symbol = symbol;

                Validator = validator;
                Formatter = formatter;
            }

            #endregion
            #region 생성자 - Symbol(symbol)

            /// <summary>
            /// 생성자
            /// </summary>
            /// <param name="symbol">상징</param>
            public Symbol(char symbol) : this(symbol, null, null)
            {
            }

            #endregion
            #region 생성자 - Symbol(symbol, validator)

            /// <summary>
            /// 생성자
            /// </summary>
            /// <param name="symbol">상징</param>
            /// <param name="validator">검증자</param>
            public Symbol(char symbol, ValidatorMethod validator) : this(symbol, validator, null)
            {
            }

            #endregion

            //////////////////////////////////////////////////////////////////////////////////////////////////// Method
            ////////////////////////////////////////////////////////////////////////////////////////// Static
            //////////////////////////////////////////////////////////////////////////////// Public

            #region 암시적 변환하기 - char(symbol)

            /// <summary>
            /// 암시적 변환하기
            /// </summary>
            /// <param name="symbol">상징</param>
            public static implicit operator char(Symbol symbol)
            {
                return symbol.Character;
            }

            #endregion

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

            #region 검증하기 - Validate(character)

            /// <summary>
            /// 검증하기
            /// </summary>
            /// <param name="character">문자</param>
            /// <returns>검증 결과</returns>
            public virtual bool Validate(char character)
            {
                if(Validator != null)
                {
                    foreach(ValidatorMethod validator in Validator.GetInvocationList())
                    {
                        if(!validator(character))
                        {
                            return false;
                        }
                    }
                }

                return true;
            }

            #endregion
            #region 포맷하기 - Format(character)

            /// <summary>
            /// 포맷하기
            /// </summary>
            /// <param name="character">문자</param>
            /// <returns>포맷 문자열</returns>
            public virtual string Format(char character)
            {
                if(Formatter != null)
                {
                    return Formatter(character).ToString();
                }

                return character.ToString();
            }

            #endregion
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 마스크
        /// </summary>
        private string mask;

        /// <summary>
        /// 상징 리스트
        /// </summary>
        private ArrayList symbolList = new ArrayList();

        #endregion

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

        #region 마스크 - Mask

        /// <summary>
        /// 마스크
        /// </summary>
        public string Mask
        {
            get
            {
                return this.mask;
            }
            set
            {
                if(this.mask == value)
                {
                    return;
                }

                this.mask = value;

                UpdateText();
            }
        }

        #endregion
        #region 상징 - SymbolList

        /// <summary>
        /// 상징
        /// </summary>
        public ArrayList SymbolList
        {
            get
            {
                return this.symbolList;
            }
        }

        #endregion
        #region 숫자 텍스트 - NumericText

        /// <summary>
        /// 숫자 텍스트
        /// </summary>
        public string NumericText
        {
            get
            {
                string text = this.textBoxBase.Text;

                StringBuilder stringBuilder = new StringBuilder();

                foreach(char character in text)
                {
                    if(char.IsDigit(character))
                    {
                        stringBuilder.Append(character);
                    }
                }

                return stringBuilder.ToString();
            }
        }

        #endregion
        
        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 -  MaskedBehavior(textBoxBase, mask)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        /// <param name="mask">마스크</param>
        public MaskedBehavior(TextBoxBase textBoxBase, string mask) : base(textBoxBase, true)
        {
            this.mask = mask;

            this.symbolList.Add(new Symbol('#', new Symbol.ValidatorMethod(char.IsDigit)));
        }

        #endregion
        #region 생성자 - MaskedBehavior(textBoxBase)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        public MaskedBehavior(TextBoxBase textBoxBase) : this(textBoxBase, string.Empty)
        {
        }

        #endregion
        #region 생성자 - MaskedBehavior(behavior)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="behavior">마스크 동작</param>
        public MaskedBehavior(MaskedBehavior behavior) : base(behavior)
        {
            this.mask            = behavior.mask;
            this.symbolList = behavior.symbolList;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Protected
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 텍스트 박스 베이스 키 DOWN 처리하기 - textBoxBase_KeyDown(sender, e)

        /// <summary>
        /// 텍스트 박스 베이스 키 DOWN 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected override void textBoxBase_KeyDown(object sender, KeyEventArgs e)
        {
            TraceLine("MaskedBehavior.textBoxBase_KeyDown " + e.KeyCode);

            if(e.KeyCode == Keys.Delete)
            {
                int startIndex;
                int endIndex;

                this.selection.GetSelection(out startIndex, out endIndex);

                string text   = this.textBoxBase.Text;
                int    length = text.Length;

                if(endIndex != length)
                {
                    if(!(endIndex == startIndex && endIndex == length - 1))
                    {
                        e.Handled = true;
                    }
                }
            }
        }

        #endregion
        #region 텍스트 박스 베이스 키 PRESS 처리하기 - textBoxBase_KeyPress(sender, e)

        /// <summary>
        /// 텍스트 박스 베이스 키 PRESS 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected override void textBoxBase_KeyPress(object sender, KeyPressEventArgs e)
        {
            TraceLine("MaskedBehavior.textBoxBase_KeyPress " + e.KeyChar);

            if(this.textBoxBase.ReadOnly)
            {
                return;
            }

            char character = e.KeyChar;

            e.Handled = true;

            int maskLength = this.mask.Length;

            if(maskLength == 0)
            {
                base.textBoxBase_KeyPress(sender, e);

                return;
            }

            int startIndex;
            int endIndex;

            this.selection.GetSelection(out startIndex, out endIndex);

            if(startIndex >= maskLength && character != (short)Keys.Back)
            {
                return;
            }

            string text   = this.textBoxBase.Text;
            int    length = text.Length;

            if(char.IsControl(character))
            {
                if(character == (short)Keys.Back && startIndex != length)
                {
                    SendKeys.Send("{LEFT}");

                    return;
                }

                base.textBoxBase_KeyPress(sender, e);

                return;
            }

            char maskCharacter = this.mask[startIndex];

            foreach(Symbol symbol in this.symbolList)
            {
                if(maskCharacter == (char)symbol)
                {
                    if(symbol.Validate(character))
                    {
                        endIndex = (endIndex == length ? endIndex : (startIndex + 1));

                        this.selection.ReplaceSelection(startIndex, endIndex, symbol.Format(character));
                    }

                    return;
                }
            }

            if(maskCharacter == character)
            {
                endIndex = (endIndex == length ? endIndex : (startIndex + 1));

                this.selection.ReplaceSelection(startIndex, endIndex, character.ToString());

                return;
            }

            StringBuilder stringBuilder = new StringBuilder();

            foreach(Symbol symbol in this.symbolList)
            {
                stringBuilder.Append((char)symbol);
            }

            char[] symbolCharacterArray = stringBuilder.ToString().ToCharArray();

            foreach(Symbol symbol in this.symbolList)
            {
                if(!symbol.Validate(character))
                {
                    continue;
                }

                string maskPortion = this.mask.Substring(startIndex);

                int maskPosition = maskPortion.IndexOfAny(symbolCharacterArray);

                if(maskPosition >= 0 && maskPortion[maskPosition] == (char)symbol)
                {
                    this.selection.ReplaceSelection
                    (
                        startIndex,
                        startIndex + maskPosition,
                        maskPortion.Substring(0, maskPosition)
                    );

                    textBoxBase_KeyPress(sender, e);

                    return;
                }
            }
        }

        #endregion

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

        #region 유효한 텍스트 구하기 - GetValidText()

        /// <summary>
        /// 유효한 텍스트 구하기
        /// </summary>
        /// <returns>유효한 텍스트</returns>
        protected override string GetValidText()
        {
            string text       = this.textBoxBase.Text;
            int    maskLength = this.mask.Length;

            if(maskLength == 0)
            {
                return text;
            }

            StringBuilder stringBuilder = new StringBuilder();

            int symbolCount = this.symbolList.Count;

            for(int position = 0, maskPosition = 0, length = text.Length; position < length; position++, maskPosition++)
            {
                char character     = text[position];
                char characterMask = (maskPosition < maskLength ? this.mask[maskPosition] : (char)0);

                if(characterMask == 0)
                {
                    break;
                }

                int symbolIndex = 0;

                for(; symbolIndex < symbolCount; symbolIndex++)
                {
                    Symbol symbol = (Symbol)this.symbolList[symbolIndex];

                    if(!symbol.Validate(character))
                    {
                        continue;
                    }

                    for(; maskPosition < maskLength; maskPosition++)
                    {
                        characterMask = this.mask[maskPosition];

                        if(characterMask == (char)symbol)
                        {
                            stringBuilder.Append(symbol.Format(character));

                            break;
                        }
                        else
                        {
                            int symbolCount2 = 0;

                            for(; symbolCount2 < symbolCount; symbolCount2++)
                            {
                                Symbol symbol2 = (Symbol)this.symbolList[symbolCount2];

                                if(characterMask == (char)symbol2)
                                {
                                    stringBuilder.Append(symbol.Format(character));

                                    break;
                                }
                            }

                            if(symbolCount2 < symbolCount)
                            {
                                break;
                            }

                            stringBuilder.Append(characterMask);
                        }
                    }

                    break;
                }

                if(symbolIndex == symbolCount)
                {
                    if(character == characterMask)
                    {
                        for(symbolIndex = 0; symbolIndex < symbolCount; symbolIndex++)
                        {
                            Symbol symbol = (Symbol)this.symbolList[symbolIndex];

                            if(characterMask == (char)symbol)
                            {
                                break;
                            }
                        }

                        if(symbolIndex == symbolCount)
                        {
                            stringBuilder.Append(character);

                            continue;
                        }
                    }

                    break;
                }
            }

            return stringBuilder.ToString();
        }

        #endregion
    }
}

 

▶ Behaviors/DateBehavior.cs

using System;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 날짜 동작
    /// </summary>
    public class DateBehavior : Behavior
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Enumeration
        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        #region 플래그 - Flag

        /// <summary>
        /// 플래그
        /// </summary>
        [Flags]
        protected enum Flag
        {
            /// <summary>
            /// DAY_BEFORE_MONTH
            /// </summary>
            DAY_BEFORE_MONTH = 0x00010000
        };

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 범위 최소값
        /// </summary>
        private DateTime rangeMinimumValue = new DateTime(1900, 1, 1);

        /// <summary>
        /// 범위 최대값
        /// </summary>
        private DateTime rangeMaximumValue = new DateTime(9998, 12, 31);

        /// <summary>
        /// 분리자
        /// </summary>
        private char separator = '/';

        #endregion

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

        #region 월 - Month

        /// <summary>
        /// 월
        /// </summary>
        public int Month
        {
            get
            {
                string text          = this.textBoxBase.Text;
                int    startPosition = GetMonthStartPosition();
                int    slash         = text.IndexOf(this.separator);

                if(startPosition != 0 && slash > 0)
                {
                    startPosition = slash + 1;
                }

                if(text.Length >= startPosition + 2)
                {
                    return ToInt(text.Substring(startPosition, 2));
                }

                return 0;
            }
            set
            {
                using(SelectionSaver savedSelection = new SelectionSaver(this.textBoxBase))
                {
                    if(Month > 0)
                    {
                        this.selection.SetSelection(GetMonthStartPosition(), GetMonthStartPosition() + 3);
                    }

                    this.selection.Replace(GetTwoDigitString(value) + this.separator);

                    AdjustMaimumxDay();

                    if(!IsValidMonth(value))
                    {
                        throw new ArgumentOutOfRangeException();
                    }
                }
            }
        }

        #endregion
        #region 일 - Day

        /// <summary>
        /// 일
        /// </summary>
        public int Day
        {
            get
            {
                string text          = this.textBoxBase.Text;
                int    startPosition = GetDayStartPosition();
                int    slash         = text.IndexOf(this.separator);

                if(startPosition != 0 && slash > 0)
                {
                    startPosition = slash + 1;
                }

                if(text.Length >= startPosition + 2)
                {
                    return ToInt(text.Substring(startPosition, 2));
                }

                return 0;
            }
            set
            {
                if(!IsValidDay(value))
                {
                    throw new ArgumentOutOfRangeException();
                }

                using(SelectionSaver savedSelection = new SelectionSaver(this.textBoxBase))
                {
                    if(Day > 0)
                    {
                        this.selection.SetSelection(GetDayStartPosition(), GetDayStartPosition() + 3);
                    }

                    this.selection.Replace(GetTwoDigitString(value) + this.separator);
                }
            }
        }

        #endregion
        #region 연도 - Year

        /// <summary>
        /// 연도
        /// </summary>
        public int Year
        {
            get
            {
                string text   = this.textBoxBase.Text;
                int    length = text.Length;
                int    slash  = text.LastIndexOf(this.separator);

                if(slash > 0 && slash < length - 1)
                {
                    return ToInt(text.Substring(slash + 1, Math.Min(4, length - slash - 1)));
                }

                return 0;
            }
            set
            {
                if(!IsValidYear(value))
                {
                    throw new ArgumentOutOfRangeException();
                }

                using(SelectionSaver selectionSaver = new SelectionSaver(this.textBoxBase))
                {
                    if(Year > 0)
                    {
                        this.selection.SetSelection(GetYearStartPosition(), GetYearStartPosition() + 4);
                    }

                    this.selection.Replace(string.Format("{0,4:0000}", value));

                    AdjustMaximumMonthAndDay();
                }
            }
        }

        #endregion
        #region 값 - Value

        /// <summary>
        /// 값
        /// </summary>
        public object Value
        {
            get
            {
                try
                {
                    return new DateTime(Year, Month, Day);
                }
                catch
                {
                    return null;
                }
            }
            set
            {
                DateTime dateTime = (DateTime)value;

                this.textBoxBase.Text = GetFormattedDate(dateTime.Year, dateTime.Month, dateTime.Day);
            }
        }

        #endregion
        #region 에러 메시지 - ErrorMessage

        /// <summary>
        /// 에러 메시지
        /// </summary>
        public override string ErrorMessage
        {
            get
            {
                return "Please specify a date between " +
                       GetFormattedDate
                       (
                           this.rangeMinimumValue.Year,
                           this.rangeMinimumValue.Month,
                           this.rangeMinimumValue.Day
                       ) +
                       " and " +
                       GetFormattedDate
                       (
                           this.rangeMaximumValue.Year,
                           this.rangeMaximumValue.Month,
                           this.rangeMaximumValue.Day
                       ) +
                       ".";
            }
        }

        #endregion
        #region 범위 최소값 - RangeMinimumValue

        /// <summary>
        /// 범위 최소값
        /// </summary>
        public DateTime RangeMinimumValue
        {
            get
            {
                return this.rangeMinimumValue;
            }
            set
            {
                if(value < new DateTime(1900, 1, 1))
                {
                    throw new ArgumentOutOfRangeException
                    (
                        "RangeMin",
                        value,
                        "Minimum value may not be older than January 1, 1900"
                    );
                }

                this.rangeMinimumValue = value;

                UpdateText();
            }
        }

        #endregion
        #region 범위 최대값 - RangeMaximumValue

        /// <summary>
        /// 범위 최대값
        /// </summary>
        public DateTime RangeMaximumValue
        {
            get
            {
                return this.rangeMaximumValue;
            }
            set
            {
                this.rangeMaximumValue = value;

                UpdateText();
            }
        }

        #endregion
        #region 분리자 - Separator

        /// <summary>
        /// 분리자
        /// </summary>
        public char Separator
        {
            get
            {
                return this.separator;
            }
            set
            {
                if(this.separator == value)
                {
                    return;
                }

                Debug.Assert(value != 0);

                Debug.Assert(!Char.IsDigit(value));

                this.separator = value;

                UpdateText();
            }
        }

        #endregion
        #region 월 앞에 일 표시 여부 - ShowDayBeforeMonth

        /// <summary>
        /// 월 앞에 일 표시 여부
        /// </summary>
        public bool ShowDayBeforeMonth
        {
            get
            {
                return HasFlag((int)Flag.DAY_BEFORE_MONTH);
            }
            set
            {
                ModifyFlags((int)Flag.DAY_BEFORE_MONTH, value);
            }
        }

        #endregion

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

        #region 생성자 - DateBehavior(textBoxBase, addEventHandlers)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        /// <param name="addEventHandlers">이벤트 핸들러 추가 여부</param>
        public DateBehavior(TextBoxBase textBoxBase, bool addEventHandlers) : base(textBoxBase, addEventHandlers)
        {
            this.separator = DateTimeFormatInfo.CurrentInfo.DateSeparator[0];

            string shortDatePattern = DateTimeFormatInfo.CurrentInfo.ShortDatePattern;

            for(int i = 0; i < shortDatePattern.Length; i++)
            {
                char character = Char.ToUpper(shortDatePattern[i]);

                if(character == 'M')
                {
                    break;
                }

                if(character == 'D')
                {
                    this.flags |= (int)Flag.DAY_BEFORE_MONTH;

                    break;
                }
            }
        }

        #endregion
        #region 생성자 - DateBehavior(textBoxBase)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="textBoxBase">텍스트 박스 베이스</param>
        public DateBehavior(TextBoxBase textBoxBase) : this(textBoxBase, true)
        {
        }

        #endregion
        #region 생성자 - DateBehavior(behavior)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="behavior">날짜 동작</param>
        public DateBehavior(DateBehavior behavior) : base(behavior)
        {
            this.rangeMinimumValue = behavior.rangeMinimumValue;
            this.rangeMaximumValue = behavior.rangeMaximumValue;
            this.separator         = behavior.separator;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 키 이벤트 처리하기 - ProcessKeyEvent(sender, e)

        /// <summary>
        /// 키 이벤트 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        public void ProcessKeyEvent(object sender, EventArgs e)
        {
            if(e is KeyEventArgs)
            {
                textBoxBase_KeyDown(sender, (KeyEventArgs)e);
            }
            else if(e is KeyPressEventArgs)
            {
                textBoxBase_KeyPress(sender, (KeyPressEventArgs)e);
            }
        }

        #endregion
        #region 날짜/시간을 위한 유효한 텍스트 구하기 - GetValidTextForDateTime()

        /// <summary>
        /// 날짜/시간을 위한 유효한 텍스트 구하기
        /// </summary>
        /// <returns>날짜/시간을 위한 유효한 텍스트</returns>
        public string GetValidTextForDateTime()
        {
            return GetValidText();
        }

        #endregion
        #region 포맷 일자 구하기 - GetFormattedDate(year, month, day)

        /// <summary>
        /// 포맷 일자 구하기
        /// </summary>
        /// <param name="year">연도</param>
        /// <param name="month">월</param>
        /// <param name="day">일</param>
        /// <returns>포맷 일자</returns>
        public string GetFormattedDate(int year, int month, int day)
        {
            if(ShowDayBeforeMonth)
            {
                return string.Format
                (
                    "{0,2:00}{1}{2,2:00}{3}{4,4:0000}",
                    day,
                    this.separator,
                    month,
                    this.separator,
                    year
                );
            }

            return string.Format
            (
                "{0,2:00}{1}{2,2:00}{3}{4,4:0000}",
                month,
                this.separator,
                day,
                this.separator,
                year
            );
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Protected
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 텍스트 박스 베이스 키 DOWN 처리하기 - textBoxBase_KeyDown(sender, e)

        /// <summary>
        /// 텍스트 박스 베이스 키 DOWN 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected override void textBoxBase_KeyDown(object sender, KeyEventArgs e)
        {
            TraceLine("DateBehavior.textBoxBase_KeyDown " + e.KeyCode);

            if(this.textBoxBase.ReadOnly)
            {
                return;
            }

            e.Handled = true;

            switch(e.KeyCode)
            {
                case Keys.Delete :
                {
                    int startIndex;
                    int endIndex;

                    this.selection.GetSelection(out startIndex, out endIndex);

                    string text   = this.textBoxBase.Text;
                    int    length = text.Length;

                    if(endIndex != length)
                    {
                        if(!(endIndex == startIndex && endIndex == length - 1))
                        {
                            return;
                        }
                    }

                    this.noTextChanged = true;

                    break;
                }
                case Keys.Up :
                {
                    int startIndex;
                    int endIndex;

                    this.selection.GetSelection(out startIndex, out endIndex);

                    if(startIndex >= GetYearStartPosition() && startIndex <= GetYearStartPosition() + 4)
                    {
                        int year = Year;

                        if(year >= this.rangeMinimumValue.Year && year < this.rangeMaximumValue.Year)
                        {
                            Year = ++year;
                        }
                    }
                    else if(startIndex >= GetMonthStartPosition() && startIndex <= GetMonthStartPosition() + 2)
                    {
                        int month = Month;

                        if(month >= GetMinimumMonth() && month < GetMaximumMonth())
                        {
                            Month = ++month;
                        }
                    }
                    else if(startIndex >= GetDayStartPosition() && startIndex <= GetDayStartPosition() + 2)
                    {
                        int day = Day;

                        if(day >= GetMinimumDay() && day < GetMaximumDay())
                        {
                            Day = ++day;
                        }
                    }

                    return;
                }
                case Keys.Down :
                {
                    int startIndex;
                    int endIndex;

                    this.selection.GetSelection(out startIndex, out endIndex);

                    if(startIndex >= GetYearStartPosition() && startIndex <= GetYearStartPosition() + 4)
                    {
                        int year = Year;

                        if(year > this.rangeMinimumValue.Year)
                        {
                            Year = --year;
                        }
                    }

                    else if(startIndex >= GetMonthStartPosition() && startIndex <= GetMonthStartPosition() + 2)
                    {
                        int month = Month;

                        if(month > GetMinimumMonth())
                        {
                            Month = --month;
                        }
                    }
                    else if(startIndex >= GetDayStartPosition() && startIndex <= GetDayStartPosition() + 2)
                    {
                        int day = Day;

                        if(day > GetMinimumDay())
                        {
                            Day = --day;
                        }
                    }

                    return;
                }
            }

            base.textBoxBase_KeyDown(sender, e);
        }

        #endregion
        #region 텍스트 박스 베이스 키 PRESS 처리하기 - textBoxBase_KeyPress(sender, e)

        /// <summary>
        /// 텍스트 박스 베이스 키 PRESS 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        protected override void textBoxBase_KeyPress(object sender, KeyPressEventArgs e)
        {
            TraceLine("DateBehavior.textBoxBase_KeyPress " + e.KeyChar);

            if(this.textBoxBase.ReadOnly)
            {
                return;
            }

            char character = e.KeyChar;

            e.Handled = true;

            this.noTextChanged = true;

            int startIndex;
            int endIndex;

            this.selection.GetSelection(out startIndex, out endIndex);

            string text   = this.textBoxBase.Text;
            int    length = text.Length;

            if(Char.IsControl(character))
            {
                if(character == (short)Keys.Back && startIndex != length)
                {
                    SendKeys.Send("{LEFT}");

                    return;
                }

                base.textBoxBase_KeyPress(sender, e);

                return;
            }

            switch(startIndex)
            {
                case 0 :
                {
                    if(ShowDayBeforeMonth)
                    {
                        if(IsValidDayDigit(character, 0))
                        {
                            if(length > startIndex)
                            {
                                this.selection.ReplaceSelection(startIndex, startIndex + 1, character.ToString());

                                if(length > startIndex + 1)
                                {
                                    if(!IsValidDay(Day))
                                    {
                                        this.selection.ReplaceSelection
                                        (
                                            startIndex + 1,
                                            startIndex + 2,
                                            GetMinimumDayDigit(1).ToString()
                                        );

                                        this.selection.SetSelection(startIndex + 1, startIndex + 2);
                                    }
                                }
                            }
                            else
                            {
                                base.textBoxBase_KeyPress(sender, e);
                            }
                        }
                        else if(length == startIndex && GetMinimumDayDigit(0) == '0' && IsValidDayDigit(character, 1))
                        {
                            this.selection.ReplaceSelection(startIndex, startIndex + 2, "0" + character);
                        }
                    }
                    else
                    {
                        if(IsValidMonthDigit(character, 0))
                        {
                            if(length > startIndex)
                            {
                                this.selection.ReplaceSelection(startIndex, startIndex + 1, character.ToString());

                                if(length > startIndex + 1)
                                {
                                    if(!IsValidMonth(Month))
                                    {
                                        this.selection.ReplaceSelection
                                        (
                                            startIndex + 1,
                                            startIndex + 2,
                                            GetMinimumMonthDigit(1).ToString()
                                        );

                                        this.selection.SetSelection(startIndex + 1, startIndex + 2);
                                    }
                                }

                                AdjustMaimumxDay();
                            }
                            else
                            {
                                base.textBoxBase_KeyPress(sender, e);
                            }
                        }
                        else if(length == startIndex && GetMinimumMonthDigit(0) == '0' && IsValidMonthDigit(character, 1))
                        {
                            this.selection.ReplaceSelection(startIndex, startIndex + 2, "0" + character);
                        }
                    }

                    break;
                }
                case 1 :
                {
                    if(ShowDayBeforeMonth)
                    {
                        if(IsValidDayDigit(character, 1))
                        {
                            if(length > startIndex)
                            {
                                this.selection.ReplaceSelection(startIndex, startIndex + 1, character.ToString());
                            }
                            else
                            {
                                base.textBoxBase_KeyPress(sender, e);
                            }
                        }
                        else if
                        (
                            character == this.separator  &&
                            length == startIndex         &&
                            GetMinimumDayDigit(0) == '0' &&
                            IsValidDay(ToInt("0" + text[0]))
                        )
                        {
                            this.selection.ReplaceSelection(0, startIndex, "0" + text[0] + character);
                        }
                    }
                    else
                    {
                        if(IsValidMonthDigit(character, 1))
                        {
                            if(length > startIndex)
                            {
                                this.selection.ReplaceSelection(startIndex, startIndex + 1, character.ToString());

                                if(Day > 0 && AdjustMaimumxDay())
                                {
                                    this.selection.SetSelection(GetDayStartPosition(), GetDayStartPosition() + 2);
                                }
                            }
                            else
                            {
                                base.textBoxBase_KeyPress(sender, e);
                            }
                        }
                        else if
                        (
                            character == this.separator    &&
                            length == startIndex           &&
                            GetMinimumMonthDigit(0) == '0' &&
                            IsValidMonth(ToInt("0" + text[0]))
                        )
                        {
                            this.selection.ReplaceSelection(0, startIndex, "0" + text[0] + character);
                        }
                    }

                    break;
                }
                case 2 :
                {
                    int slash = 0;

                    if(character == this.separator)
                    {
                        slash = 1;
                    }
                    else
                    {
                        if(ShowDayBeforeMonth)
                        {
                            slash = (IsValidMonthDigit(character, 0) ||
                                    (length == startIndex && GetMinimumMonthDigit(0) == '0' && IsValidMonthDigit(character, 1))) ? 2 : 0;
                        }
                        else
                        {
                            slash = (IsValidDayDigit(character, 0) ||
                                    (length == startIndex && GetMinimumDayDigit(0) == '0' && IsValidDayDigit(character, 1))) ? 2 : 0;
                        }
                    }

                    if(slash != 0)
                    {
                        this.selection.ReplaceSelection(startIndex, startIndex + 1, this.separator.ToString());
                    }

                    if(slash == 2)
                    {
                        SendKeys.Send(character.ToString());
                    }

                    break;
                }
                case 3 :
                {
                    if(ShowDayBeforeMonth)
                    {
                        if(IsValidMonthDigit(character, 0))
                        {
                            if(length > startIndex)
                            {
                                this.selection.ReplaceSelection(startIndex, startIndex + 1, character.ToString());

                                if(length > startIndex + 1)
                                {
                                    if(!IsValidMonth(Month))
                                    {
                                        this.selection.ReplaceSelection(startIndex + 1, startIndex + 2, GetMinimumMonthDigit(1).ToString());

                                        this.selection.SetSelection(startIndex + 1, startIndex + 2);
                                    }
                                }
                            }
                            else
                            {
                                base.textBoxBase_KeyPress(sender, e);
                            }

                            AdjustMaimumxDay();
                        }
                        else if(length == startIndex && GetMinimumMonthDigit(0) == '0' && IsValidMonthDigit(character, 1))
                        {
                            this.selection.ReplaceSelection(startIndex, startIndex + 2, "0" + character);

                            AdjustMaimumxDay();
                        }
                    }
                    else
                    {
                        if(IsValidDayDigit(character, 0))
                        {
                            if(length > startIndex)
                            {
                                this.selection.ReplaceSelection(startIndex, startIndex + 1, character.ToString());

                                if(length > startIndex + 1)
                                {
                                    if(!IsValidDay(Day))
                                    {
                                        this.selection.ReplaceSelection(startIndex + 1, startIndex + 2, GetMinimumDayDigit(1).ToString());

                                        this.selection.SetSelection(startIndex + 1, startIndex + 2);
                                    }
                                }
                            }
                            else
                            {
                                base.textBoxBase_KeyPress(sender, e);
                            }
                        }
                        else if(length == startIndex && GetMinimumDayDigit(0) == '0' && IsValidDayDigit(character, 1))
                        {
                            this.selection.ReplaceSelection(startIndex, startIndex + 2, "0" + character);
                        }
                    }

                    break;
                }
                case 4 :
                {
                    if(ShowDayBeforeMonth)
                    {
                        if(IsValidMonthDigit(character, 1))
                        {
                            if(length > startIndex)
                            {
                                this.selection.ReplaceSelection(startIndex, startIndex + 1, character.ToString());

                                if(Day > 0 && AdjustMaimumxDay())
                                {
                                    this.selection.SetSelection(GetDayStartPosition(), GetDayStartPosition() + 2);
                                }
                            }
                            else
                            {
                                base.textBoxBase_KeyPress(sender, e);

                                AdjustMaimumxDay();
                            }
                        }
                        else if
                        (
                            character == this.separator    &&
                            length == startIndex           &&
                            GetMinimumMonthDigit(0) == '0' &&
                            IsValidMonth(ToInt("0" + text[3]))
                        )
                        {
                            this.selection.ReplaceSelection(3, startIndex, "0" + text[3] + character);
                        }
                    }
                    else
                    {
                        if(IsValidDayDigit(character, 1))
                        {
                            if(length > startIndex)
                            {
                                this.selection.ReplaceSelection(startIndex, startIndex + 1, character.ToString());
                            }
                            else
                            {
                                base.textBoxBase_KeyPress(sender, e);
                            }
                        }
                        else if
                        (
                            character == this.separator  &&
                            length == startIndex         &&
                            GetMinimumDayDigit(0) == '0' &&
                            IsValidDay(ToInt("0" + text[3]))
                        )
                        {
                            this.selection.ReplaceSelection(3, startIndex, "0" + text[3] + character);
                        }
                    }

                    break;
                }
                case 5 :
                {
                    int slash = 0;

                    if(character == this.separator)
                    {
                        slash = 1;
                    }
                    else
                    {
                        slash = (IsValidYearDigit(character, 0) ? 2 : 0);
                    }

                    if(slash != 0)
                    {
                        this.selection.ReplaceSelection(startIndex, startIndex + 1, this.separator.ToString());
                    }

                    if(slash == 2)
                    {
                        SendKeys.Send(character.ToString());
                    }

                    break;
                }
                case 6 :
                case 7 :
                case 8 :
                case 9 :
                {
                    if(IsValidYearDigit(character, startIndex - GetYearStartPosition()))
                    {
                        if(length > startIndex)
                        {
                            this.selection.ReplaceSelection(startIndex, startIndex + 1, character.ToString());

                            for(; startIndex + 1 < length && startIndex < 9; startIndex++)
                            {
                                if(!IsValidYearDigit(text[startIndex + 1], startIndex - (GetYearStartPosition() - 1)))
                                {
                                    this.selection.SetSelection(startIndex + 1, 10);

                                    StringBuilder stringBuilder = new StringBuilder();

                                    for(int i = startIndex + 1; i < length && i < 10; i++)
                                    {
                                        stringBuilder.Append(GetMinimumYearDigit(i - GetYearStartPosition(), false));
                                    }

                                    this.selection.Replace(stringBuilder.ToString());

                                    this.selection.SetSelection(startIndex + 1, 10);

                                    break;
                                }
                            }
                        }
                        else
                        {
                            base.textBoxBase_KeyPress(sender, e);
                        }

                        if(IsValidYear(Year))
                        {
                            AdjustMaimumxDay();

                            AdjustMaximumMonthAndDay();
                        }
                    }

                    break;
                }
            }
        }

        #endregion

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

        #region 2자리 숫자 문자열 구하기 - GetTwoDigitString(value)

        /// <summary>
        /// 2자리 숫자 문자열 구하기
        /// </summary>
        /// <param name="value">값</param>
        /// <returns>2자리 숫자 문자열</returns>
        protected static string GetTwoDigitString(int value)
        {
            return string.Format("{0,2:00}", value);
        }

        #endregion
        #region 월 시작 위치 구하기 - GetMonthStartPosition()

        /// <summary>
        /// 월 시작 위치 구하기
        /// </summary>
        /// <returns>월 시작 위치</returns>
        protected int GetMonthStartPosition()
        {
            return ShowDayBeforeMonth ? 3 : 0;
        }

        #endregion
        #region 일 시작 위치 구하기 - GetDayStartPosition()

        /// <summary>
        /// 일 시작 위치 구하기
        /// </summary>
        /// <returns>일 시작 위치</returns>
        protected int GetDayStartPosition()
        {
            return ShowDayBeforeMonth ? 0 : 3;
        }

        #endregion
        #region 연도 시작 위치 구하기 - GetYearStartPosition()

        /// <summary>
        /// 연도 시작 위치 구하기
        /// </summary>
        /// <returns>연도 시작 위치</returns>
        protected int GetYearStartPosition()
        {
            return 6;
        }

        #endregion
        #region 최대 월 구하기 - GetMaximumMonth()

        /// <summary>
        /// 최대 월 구하기
        /// </summary>
        /// <returns>최대 월</returns>
        protected int GetMaximumMonth()
        {
            if(GetValidYear() == this.rangeMaximumValue.Year)
            {
                return this.rangeMaximumValue.Month;
            }

            return 12;
        }

        #endregion
        #region 최소 월 구하기 - GetMinimumMonth()

        /// <summary>
        /// 최소 월 구하기
        /// </summary>
        /// <returns>최소 월</returns>
        protected int GetMinimumMonth()
        {
            if(GetValidYear() == this.rangeMinimumValue.Year)
            {
                return this.rangeMinimumValue.Month;
            }

            return 1;
        }

        #endregion
        #region 최대 일 구하기 - GetMaximumDay()

        /// <summary>
        /// 최대 일 구하기
        /// </summary>
        /// <returns></returns>
        protected int GetMaximumDay()
        {
            int year  = GetValidYear();
            int month = GetValidMonth();

            if(year == this.rangeMaximumValue.Year && month == this.rangeMaximumValue.Month)
            {
                return this.rangeMaximumValue.Day;
            }

            return GetDayCountOfMonth(month, year);
        }

        #endregion
        #region 최소 일 구하기 - GetMinimumDay()

        /// <summary>
        /// 최소 일 구하기
        /// </summary>
        /// <returns>최소 일</returns>
        protected int GetMinimumDay()
        {
            int year  = GetValidYear();
            int month = GetValidMonth();

            if(year == this.rangeMinimumValue.Year && month == this.rangeMinimumValue.Month)
            {
                return this.rangeMinimumValue.Day;
            }

            return 1;
        }

        #endregion
        #region 월의 일 카운트 구하기 - GetDayCountOfMonth(month, year)

        /// <summary>
        /// 월의 일 카운트 구하기
        /// </summary>
        /// <param name="month">월</param>
        /// <param name="year">연도</param>
        /// <returns>월의 일 카운트</returns>
        protected static int GetDayCountOfMonth(int month, int year)
        {
            Debug.Assert(month >= 1 && month <= 12);

            switch(month)
            {
                case 4  :
                case 6  :
                case 9  :
                case 11 : return 30;
                case 2  : return DateTime.IsLeapYear(year) ? 29 : 28;
            }

            return 31;
        }

        #endregion
        #region 최대 월 숫자 구하기 - GetMaximumMonthDigit(position)

        /// <summary>
        /// 최대 월 숫자 구하기
        /// </summary>
        /// <param name="position">위치</param>
        /// <returns>최대 월 숫자</returns>
        protected char GetMaximumMonthDigit(int position)
        {
            Debug.Assert(position >= 0 && position <= 1);

            int year         = GetValidYear();
            int maximumMonth = this.rangeMaximumValue.Month;
            int maximumYear  = this.rangeMaximumValue.Year;

            if(position == 0)
            {
                if(year == maximumYear)
                {
                    return GetTwoDigitString(maximumMonth)[0];
                }

                return '1';
            }

            string text = this.textBoxBase.Text;

            char firstDigit = (text.Length > GetMonthStartPosition()) ? text[GetMonthStartPosition()] : '0';

            Debug.Assert(firstDigit != 0);

            if(year == maximumYear && (IsValidYear(Year) || maximumYear == this.rangeMinimumValue.Year))
            {
                if(GetTwoDigitString(maximumMonth)[0] == firstDigit)
                {
                    return GetTwoDigitString(maximumMonth)[1];
                }

                Debug.Assert(firstDigit == '0');

                return '9';
            }

            return (firstDigit == '1' ? '2' : '9');
        }

        #endregion
        #region 최소 월 숫자 구하기 - GetMinimumMonthDigit(position)

        /// <summary>
        /// 최소 월 숫자 구하기
        /// </summary>
        /// <param name="position">위치</param>
        /// <returns>최대 월 숫자</returns>
        protected char GetMinimumMonthDigit(int position)
        {
            Debug.Assert(position >= 0 && position <= 1);

            int year         = GetValidYear();
            int minimumMonth = this.rangeMinimumValue.Month;
            int minimumYear  = this.rangeMinimumValue.Year;

            if(position == 0)
            {
                if(year == minimumYear)
                {
                    return GetTwoDigitString(minimumMonth)[0];
                }

                return '0';
            }

            string text = this.textBoxBase.Text;

            char firstDigit = (text.Length > GetMonthStartPosition()) ? text[GetMonthStartPosition()] : '0';

            if(firstDigit == 0)
            {
                return '1';
            }

            if(year == minimumYear && (IsValidYear(Year) || minimumYear == this.rangeMaximumValue.Year))
            {
                if(GetTwoDigitString(minimumMonth)[0] == firstDigit)
                {
                    return GetTwoDigitString(minimumMonth)[1];
                }

                return '0';
            }

            return (firstDigit == '1' ? '0' : '1');
        }

        #endregion
        #region 월 숫자 유효성 여부 구하기 - IsValidMonthDigit(character, position)

        /// <summary>
        /// 월 숫자 유효성 여부 구하기
        /// </summary>
        /// <param name="character">문자</param>
        /// <param name="position">위치</param>
        /// <returns>월 숫자 유효성 여부</returns>
        protected bool IsValidMonthDigit(char character, int position)
        {
            return (character >= GetMinimumMonthDigit(position) && character <= GetMaximumMonthDigit(position));
        }

        #endregion
        #region 월 유효성 여부 구하기 - IsValidMonth(month)

        /// <summary>
        /// 월 유효성 여부 구하기
        /// </summary>
        /// <param name="month">월</param>
        /// <returns>월 유효성 여부</returns>
        protected bool IsValidMonth(int month)
        {
            int year = GetValidYear();
            int day  = GetValidDay();

            try
            {
                return IsWithinRange(new DateTime(year, month, day));
            }
            catch
            {
                return false;
            }
        }

        #endregion
        #region 최대 일 숫자 구하기 - GetMaximumDayDigit(position)

        /// <summary>
        /// 최대 일 숫자 구하기
        /// </summary>
        /// <param name="position">위치</param>
        /// <returns>최대 일 숫자</returns>
        protected char GetMaximumDayDigit(int position)
        {
            Debug.Assert(position >= 0 && position <= 1);

            int month        = GetValidMonth();
            int year         = GetValidYear();
            int maximumDay   = this.rangeMaximumValue.Day;
            int maximumMonth = this.rangeMaximumValue.Month;
            int maximumYear  = this.rangeMaximumValue.Year;

            if(position == 0)
            {
                if(year == maximumYear && month == maximumMonth)
                {
                    return GetTwoDigitString(maximumDay)[0];
                }

                return GetTwoDigitString(GetDayCountOfMonth(month, year))[0];
            }

            string text = this.textBoxBase.Text;

            char firstDigit = (text.Length > GetDayStartPosition()) ? text[GetDayStartPosition()] : '0';

            Debug.Assert(firstDigit != 0);

            if(year == maximumYear && month == maximumMonth && GetTwoDigitString(maximumDay)[0] == firstDigit)
            {
                return GetTwoDigitString(maximumDay)[1];
            }

            if(firstDigit == '0' || firstDigit == '1' || (firstDigit == '2' && month != 2) || (month == 2 && !IsValidYear(Year)))
            {
                return '9';
            }

            return GetTwoDigitString(GetDayCountOfMonth(month, year))[1];
        }

        #endregion
        #region 최소 일 숫자 구하기 - GetMinimumDayDigit(position)

        /// <summary>
        /// 최소 일 숫자 구하기
        /// </summary>
        /// <param name="position">위치</param>
        /// <returns>최소 일 숫자</returns>
        protected char GetMinimumDayDigit(int position)
        {
            Debug.Assert(position >= 0 && position <= 1);

            int month        = GetValidMonth();
            int year         = GetValidYear();
            int minimumDay   = this.rangeMinimumValue.Day;
            int minimumMonth = this.rangeMinimumValue.Month;
            int minimumYear  = this.rangeMinimumValue.Year;

            if(position == 0)
            {
                if(year == minimumYear && month == minimumMonth)
                {
                    return GetTwoDigitString(minimumDay)[0];
                }

                return '0';
            }

            string text = this.textBoxBase.Text;

            char firstDigit = (text.Length > GetDayStartPosition()) ? text[GetDayStartPosition()] : '0';

            if(firstDigit == 0)
            {
                return '1';
            }

            if(year == minimumYear && month == minimumMonth && GetTwoDigitString(minimumDay)[0] == firstDigit)
            {
                return GetTwoDigitString(minimumDay)[1];
            }

            return (firstDigit == '0' ? '1' : '0');
        }

        #endregion
        #region 일 숫자 유효성 여부 구하기 - IsValidDayDigit(character, position)

        /// <summary>
        /// 일 숫자 유효성 여부 구하기
        /// </summary>
        /// <param name="character">문자</param>
        /// <param name="position">위치</param>
        /// <returns>일 숫자 유효성 여부</returns>
        protected bool IsValidDayDigit(char character, int position)
        {
            return (character >= GetMinimumDayDigit(position) && character <= GetMaximumDayDigit(position));
        }

        #endregion
        #region 일 유효성 여부 구하기 - IsValidDay(day)

        /// <summary>
        /// 일 유효성 여부 구하기
        /// </summary>
        /// <param name="day">일</param>
        /// <returns>일 유효성 여부</returns>
        protected bool IsValidDay(int day)
        {
            try
            {
                return IsWithinRange(new DateTime(GetValidYear(), GetValidMonth(), day));
            }
            catch
            {
                return false;
            }
        }

        #endregion
        #region 연도 유효성 여부 구하기 - IsValidYear(year)

        /// <summary>
        /// 연도 유효성 여부 구하기
        /// </summary>
        /// <param name="year">연도</param>
        /// <returns>연도 유효성 여부</returns>
        protected bool IsValidYear(int year)
        {
            return (year >= this.rangeMinimumValue.Year && year <= this.rangeMaximumValue.Year);
        }

        #endregion
        #region 최대 일 조정하기 - AdjustMaimumxDay()

        /// <summary>
        /// 최대 일 조정하기
        /// </summary>
        /// <returns>처리 결과</returns>
        protected bool AdjustMaimumxDay()
        {
            int day = Day;

            if(day != 0 && !IsValidDay(day))
            {
                Day = GetMaximumDay();

                return true;
            }

            return false;
        }

        #endregion
        #region 최대 월/일 조정하기 - AdjustMaximumMonthAndDay()

        /// <summary>
        /// 최대 월/일 조정하기
        /// </summary>
        /// <returns></returns>
        protected bool AdjustMaximumMonthAndDay()
        {
            int month = Month;

            if(month != 0 && !IsValidMonth(month))
            {
                Month = GetMinimumMonth();

                return true;
            }

            return AdjustMaimumxDay();
        }

        #endregion
        #region 최대 연도 숫자 구하기 - GetMaximumYearDigit(position)

        /// <summary>
        /// 최대 연도 숫자 구하기
        /// </summary>
        /// <param name="position">위치</param>
        /// <returns>최대 연도 숫자</returns>
        protected char GetMaximumYearDigit(int position)
        {
            Debug.Assert(position >= 0 && position <= 3);

            string year        = string.Empty + Year;
            string maximumYear = string.Empty + this.rangeMaximumValue.Year;

            if(position == 0 || ToInt(maximumYear.Substring(0, position)) <= ToInt(year.Substring(0, position)))
            {
                return maximumYear[position];
            }

            return '9';
        }

        #endregion
        #region 최소 연도 숫자 구하기 - GetMinimumYearDigit(position, validYear)

        /// <summary>
        /// 최소 연도 숫자 구하기
        /// </summary>
        /// <param name="position">위치</param>
        /// <param name="validYear">연도 유효 여부</param>
        /// <returns>최소 연도 숫자</returns>
        protected char GetMinimumYearDigit(int position, bool validYear)
        {
            Debug.Assert(position >= 0 && position <= 3);

            int year = Year;

            if(validYear && !IsValidYear(year))
            {
                year = GetValidYear();
            }

            string yearString        = string.Empty + year;
            string minimumYearString = string.Empty + this.rangeMinimumValue.Year;

            if(position == 0 || ToInt(minimumYearString.Substring(0, position)) >= ToInt(yearString.Substring(0, position)))
            {
                return minimumYearString[position];
            }

            return '0';
        }

        #endregion
        #region 연도 숫자 유효성 여부 구하기 - IsValidYearDigit(character, position)

        /// <summary>
        /// 연도 숫자 유효성 여부 구하기
        /// </summary>
        /// <param name="character">문자</param>
        /// <param name="position">위치</param>
        /// <returns>연도 숫자 유효성 여부</returns>
        protected bool IsValidYearDigit(char character, int position)
        {
            return (character >= GetMinimumYearDigit(position, false) && character <= GetMaximumYearDigit(position));
        }

        #endregion
        #region 유효한 월 구하기 - GetValidMonth()

        /// <summary>
        /// 유효한 월 구하기
        /// </summary>
        /// <returns>유효한 월</returns>
        protected int GetValidMonth()
        {
            int month = Month;

            if(month < GetMinimumMonth())
            {
                month = GetMinimumMonth();
            }
            else if(month > GetMaximumMonth())
            {
                month = GetMaximumMonth();
            }

            return month;
        }

        #endregion
        #region 유효한 일 구하기 - GetValidDay()

        /// <summary>
        /// 유효한 일 구하기
        /// </summary>
        /// <returns>유효한 일</returns>
        protected int GetValidDay()
        {
            int day = Day;

            if(day < GetMinimumDay())
            {
                day = GetMinimumDay();
            }
            else if(day > GetMaximumDay())
            {
                day = GetMaximumDay();
            }

            return day;
        }

        #endregion
        #region 유효한 연도 구하기 - GetValidYear()

        /// <summary>
        /// 유효한 연도 구하기
        /// </summary>
        /// <returns>유효한 연도</returns>
        protected int GetValidYear()
        {
            int year = Year;

            if(year < this.rangeMinimumValue.Year)
            {
                year = DateTime.Today.Year;

                if(year < this.rangeMinimumValue.Year)
                {
                    year = this.rangeMinimumValue.Year;
                }
            }

            if(year > this.rangeMaximumValue.Year)
            {
                year = this.rangeMaximumValue.Year;
            }

            return year;
        }

        #endregion
        #region 일자 설정하기 - SetDate(year, month, day)

        /// <summary>
        /// 일자 설정하기
        /// </summary>
        /// <param name="year">연도</param>
        /// <param name="month">월</param>
        /// <param name="day">일</param>
        public void SetDate(int year, int month, int day)
        {
            Value = new DateTime(year, month, day);
        }

        #endregion
        #region 유효성 여부 구하기 - IsValid()

        /// <summary>
        /// 유효성 여부 구하기
        /// </summary>
        /// <returns>유효성 여부</returns>
        public override bool IsValid()
        {
            try
            {
                return IsWithinRange(new DateTime(Year, Month, Day));
            }
            catch
            {
                return false;
            }
        }

        #endregion
        #region 범위 내 여부 구하기 - IsWithinRange(dateTime)

        /// <summary>
        /// 범위 내 여부 구하기
        /// </summary>
        /// <param name="dateTime">날짜/시간</param>
        /// <returns>범위 내 여부</returns>
        public bool IsWithinRange(DateTime dateTime)
        {
            DateTime date = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day);

            return (date >= this.rangeMinimumValue && date <= this.rangeMaximumValue);
        }

        #endregion
        #region 유효한 텍스트 구하기 - GetValidText()

        /// <summary>
        /// 유효한 텍스트 구하기
        /// </summary>
        /// <returns>유효한 텍스트</returns>
        protected override string GetValidText()
        {
            string text = this.textBoxBase.Text;

            if(text == string.Empty)
            {
                return text;
            }

            if(IsValid())
            {
                return GetFormattedDate(Year, Month, Day);
            }

            if(Year == 0 && Month == 0 && Day == 0)
            {
                Value = DateTime.Today;
            }

            int year  = GetValidYear();
            int month = GetValidMonth();
            int day   = GetValidDay();

            if(!IsWithinRange(new DateTime(year, month, day)))
            {
                month = GetMinimumMonth();
            }

            if(!IsWithinRange(new DateTime(year, month, day)))
            {
                day = GetMaximumDay();
            }

            return GetFormattedDate(year, month, day);
        }

        #endregion
    }
}

 

▶ Controls/TextBox.cs

using System;
using System.ComponentModel;
using System.Windows.Forms.Design;

namespace TestProject
{
    /// <summary>
    /// 텍스트 박스
    /// </summary>
    [Browsable(false)]
    [Designer(typeof(TextBox.Designer))]
    public abstract class TextBox : System.Windows.Forms.TextBox
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Class
        ////////////////////////////////////////////////////////////////////////////////////////// Internal

        #region 디자이너 - Designer

        /// <summary>
        /// 디자이너
        /// </summary>
        internal class Designer : ControlDesigner
        {
            //////////////////////////////////////////////////////////////////////////////////////////////////// Method
            ////////////////////////////////////////////////////////////////////////////////////////// Public

            #region 컴포넌트 디폴트 설정시 처리하기 - OnSetComponentDefaults()

            /// <summary>
            /// 컴포넌트 디폴트 설정시 처리하기
            /// </summary>
            [Obsolete]
            public override void OnSetComponentDefaults()
            {
            }

            #endregion
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        #region Field

        /// <summary>
        /// 동작
        /// </summary>
        protected Behavior behavior = null;

        #endregion

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

        #region 플래그 - Flags

        /// <summary>
        /// 플래그
        /// </summary>
        [Category("Behavior")]
        [Description("The flags (on/off attributes) associated with the Behavior.")]
        public int Flags
        {
            get
            {
                return this.behavior.Flags;
            }
            set
            {
                this.behavior.Flags = value;
            }
        }

        #endregion
        #region 에러 메시지 - ErrorMessage

        /// <summary>
        /// 에러 메시지
        /// </summary>
        [Browsable(false)]
        public string ErrorMessage
        {
            get
            {
                return this.behavior.ErrorMessage;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        #region 생성자 - TextBox

        /// <summary>
        /// 생성자
        /// </summary>
        protected TextBox()
        {
        }

        #endregion
        #region 생성자 - TextBox(behavior)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="behavior">동작</param>
        protected TextBox(Behavior behavior)
        {
            this.behavior = behavior;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 텍스트 갱신하기 - UpdateText()

        /// <summary>
        /// 텍스트 갱신하기
        /// </summary>
        /// <returns>처리 결과</returns>
        public bool UpdateText()
        {
            return this.behavior.UpdateText();
        }

        #endregion
        #region 플래그 수정하기 - ModifyFlags(flags, added)

        /// <summary>
        /// 플래그 수정하기
        /// </summary>
        /// <param name="flags">플래그</param>
        /// <param name="added">추가 여부</param>
        public void ModifyFlags(int flags, bool added)
        {
            this.behavior.ModifyFlags(flags, added);
        }

        #endregion
        #region 검증하기 - Validate()

        /// <summary>
        /// 검증하기
        /// </summary>
        /// <returns>검증 결과</returns>
        public bool Validate()
        {
            return this.behavior.Validate();
        }

        #endregion
        #region 유효성 여부 구하기 - IsValid()

        /// <summary>
        /// 유효성 여부 구하기
        /// </summary>
        /// <returns>유효성 여부</returns>
        public bool IsValid()
        {
            return this.behavior.IsValid();
        }

        #endregion
        #region 에러 메시지 박스 표시하기 - ShowErrorMessageBox(message)

        /// <summary>
        /// 에러 메시지 박스 표시하기
        /// </summary>
        /// <param name="message">메시지</param>
        public void ShowErrorMessageBox(string message)
        {
            this.behavior.ShowErrorMessageBox(message);
        }

        #endregion
        #region 에러 아이콘 표시하기 - ShowErrorIcon(message)

        /// <summary>
        /// 에러 아이콘 표시하기
        /// </summary>
        /// <param name="message">메시지</param>
        public void ShowErrorIcon(string message)
        {
            this.behavior.ShowErrorIcon(message);
        }

        #endregion
    }
}

 

▶ Controls/NumericTextBox.cs

using System;
using System.ComponentModel;
using System.Collections;

namespace TestProject
{
    /// <summary>
    /// 숫자 텍스트 박스
    /// </summary>
    [Designer(typeof(NumericTextBox.Designer))]
    public class NumericTextBox : TestProject.TextBox
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 디자이너 - Designer

        /// <summary>
        /// 디자이너
        /// </summary>
        internal new class Designer : TextBox.Designer
        {
            //////////////////////////////////////////////////////////////////////////////////////////////////// Method
            ////////////////////////////////////////////////////////////////////////////////////////// Protected

            #region 속성 필터 처리하기 - PostFilterProperties(propertyDictionary)

            /// <summary>
            /// 속성 필터 처리하기
            /// </summary>
            /// <param name="propertyDictionary">속성 딕셔너리</param>
            protected override void PostFilterProperties(IDictionary propertyDictionary)
            {
                propertyDictionary.Remove("DecimalPoint"  );
                propertyDictionary.Remove("GroupSeparator");
                propertyDictionary.Remove("NegativeSign"  );
                propertyDictionary.Remove("Double"        );
                propertyDictionary.Remove("Int"           );
                propertyDictionary.Remove("Long"          );

                base.PostFilterProperties(propertyDictionary);
            }

            #endregion
        }

        #endregion

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

        #region 실수 - Double

        /// <summary>
        /// 실수
        /// </summary>
        [Browsable(false)]
        public double Double
        {
            get
            {
                try
                {
                    return Convert.ToDouble(Behavior.NumericText);
                }
                catch
                {
                    return 0;
                }
            }
            set
            {
                Text = value.ToString();
            }
        }

        #endregion
        #region 정수 - Int

        /// <summary>
        /// 정수
        /// </summary>
        [Browsable(false)]
        public int Int
        {
            get
            {
                try
                {
                    return Convert.ToInt32(Behavior.NumericText);
                }
                catch
                {
                    return 0;
                }
            }
            set
            {
                Text = value.ToString();
            }
        }

        #endregion
        #region 배정도 정수 - Long

        /// <summary>
        /// 배정도 정수
        /// </summary>
        [Browsable(false)]
        public long Long
        {
            get
            {
                try
                {
                    return Convert.ToInt64(Behavior.NumericText);
                }
                catch
                {
                    return 0;
                }
            }
            set
            {
                Text = value.ToString();
            }
        }

        #endregion
        #region 숫자 텍스트 - NumericText

        /// <summary>
        /// 숫자 텍스트
        /// </summary>
        [Browsable(false)]
        public string NumericText
        {
            get
            {
                return Behavior.NumericText;
            }
        }

        #endregion
        #region 실제 숫자 텍스트 - RealNumericText

        /// <summary>
        /// 실제 숫자 텍스트
        /// </summary>
        [Browsable(false)]
        public string RealNumericText
        {
            get
            {
                return Behavior.RealNumericText;
            }
        }

        #endregion
        #region 최대 전체 숫자 카운트 - MaximumWholeDigitCount

        /// <summary>
        /// 최대 전체 숫자 카운트
        /// </summary>
        [Category("Behavior")]
        [Description("The maximum number of digits allowed left of the decimal point.")]
        public int MaximumWholeDigitCount
        {
            get
            {
                return Behavior.MaximumWholeDigitCount;
            }
            set
            {
                Behavior.MaximumWholeDigitCount = value;
            }
        }

        #endregion
        #region 최대 소수점 이하 자리 카운트 - MaximumDecimalPlaceCount

        /// <summary>
        /// 최대 소수점 이하 자리 카운트
        /// </summary>
        [Category("Behavior")]
        [Description("The maximum number of digits allowed right of the decimal point.")]
        public int MaximumDecimalPlaceCount
        {
            get
            {
                return Behavior.MaximumDecimalPlaceCount;
            }
            set
            {
                Behavior.MaximumDecimalPlaceCount = value;
            }
        }

        #endregion
        #region 음수 허용 여부 - AllowNegative

        /// <summary>
        /// 음수 허용 여부
        /// </summary>
        [Category("Behavior")]
        [Description("Determines whether the value is allowed to be negative or not.")]
        public bool AllowNegative
        {
            get
            {
                return Behavior.AllowNegative;
            }
            set
            {
                Behavior.AllowNegative = value;
            }
        }

        #endregion
        #region 그룹 내 숫자 카운트 - DigitCountInGroup

        /// <summary>
        /// 그룹 내 숫자 카운트
        /// </summary>
        [Category("Behavior")]
        [Description("The number of digits to place in each group to the left of the decimal point.")]
        public int DigitCountInGroup
        {
            get
            {
                return Behavior.DigitCountInGroup;
            }
            set
            {
                Behavior.DigitCountInGroup = value;
            }
        }

        #endregion
        #region 소수점 - DecimalPoint

        /// <summary>
        /// 소수점
        /// </summary>
        [Browsable(false)]
        public char DecimalPoint
        {
            get
            {
                return Behavior.DecimalPoint;
            }
            set
            {
                Behavior.DecimalPoint = value;
            }
        }

        #endregion
        #region 그룹 분리자 - GroupSeparator

        /// <summary>
        /// 그룹 분리자
        /// </summary>
        [Browsable(false)]
        public char GroupSeparator
        {
            get
            {
                return Behavior.GroupSeparator;
            }
            set
            {
                Behavior.GroupSeparator = value;
            }
        }

        #endregion
        #region 음수 기호 - NegativeSign

        /// <summary>
        /// 음수 기호
        /// </summary>
        [Browsable(false)]
        public char NegativeSign
        {
            get
            {
                return Behavior.NegativeSign;
            }
            set
            {
                Behavior.NegativeSign = value;
            }
        }

        #endregion
        #region 접두사 - Prefix

        /// <summary>
        /// 접두사
        /// </summary>
        [Category("Behavior")]
        [Description("The text to automatically insert in front of the number, such as a currency symbol.")]
        public String Prefix
        {
            get
            {
                return Behavior.Prefix;
            }
            set
            {
                Behavior.Prefix = value;
            }
        }

        #endregion
        #region 범위 최소값 - RangeMinimumValue

        /// <summary>
        /// 범위 최소값
        /// </summary>
        [Category("Behavior")]
        [Description("The minimum value allowed.")]
        public double RangeMinimumValue
        {
            get
            {
                return Behavior.RangeMinimumValue;
            }
            set
            {
                Behavior.RangeMinimumValue = value;
            }
        }

        #endregion
        #region 범위 최대값 - RangeMaximumValue

        /// <summary>
        /// 범위 최대값
        /// </summary>
        [Category("Behavior")]
        [Description("The maximum value allowed.")]
        public double RangeMaximumValue
        {
            get
            {
                return Behavior.RangeMaximumValue;
            }
            set
            {
                Behavior.RangeMaximumValue = value;
            }
        }

        #endregion

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

        #region 동작 - Behavior

        /// <summary>
        /// 동작
        /// </summary>
        [Browsable(false)]
        public NumericBehavior Behavior
        {
            get
            {
                return (NumericBehavior)this.behavior;
            }
        }

        #endregion

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

        #region 생성자 - NumericTextBox()

        /// <summary>
        /// 생성자
        /// </summary>
        public NumericTextBox()
        {
            this.behavior = new NumericBehavior(this);
        }

        #endregion
        #region 생성자 - NumericTextBox(maximumWholeDigitCount, maximumDecimalPlacesCount)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="maximumWholeDigitCount">최대 전체 숫자 카운트</param>
        /// <param name="maximumDecimalPlacesCount">최대 소수점 이하 자리 카운트</param>
        public NumericTextBox(int maximumWholeDigitCount, int maximumDecimalPlacesCount)
        {
            this.behavior = new NumericBehavior(this, maximumWholeDigitCount, maximumDecimalPlacesCount);
        }

        #endregion
        #region 생성자 - NumericTextBox(behavior)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="behavior">숫자 동작</param>
        public NumericTextBox(NumericBehavior behavior) : base(behavior)
        {
        }

        #endregion
    }
}

 

▶ Controls/IntegerTextBox.cs

namespace TestProject
{
    /// <summary>
    /// 정수 텍스트 박스
    /// </summary>
    public class IntegerTextBox : NumericTextBox
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - IntegerTextBox()

        /// <summary>
        /// 생성자
        /// </summary>
        public IntegerTextBox() : base(null)
        {
            this.behavior = new IntegerBehavior(this);
        }

        #endregion
        #region 생성자 - IntegerTextBox(maximumWholeDigitCount)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="maximumWholeDigitCount">최대 전체 숫자 카운트</param>
        public IntegerTextBox(int maximumWholeDigitCount) : base(null)
        {
            this.behavior = new IntegerBehavior(this, maximumWholeDigitCount);
        }

        #endregion
        #region 생성자 - IntegerTextBox(behavior)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="behavior">정수 동작</param>
        public IntegerTextBox(IntegerBehavior behavior) : base(behavior)
        {
        }

        #endregion
    }
}

 

▶ Controls/CurrencyTextBox.cs

using System.ComponentModel;
using System.Collections;

namespace TestProject
{
    /// <summary>
    /// 통화 텍스트 박스
    /// </summary>
    [Designer(typeof(CurrencyTextBox.Designer))]
    public class CurrencyTextBox : NumericTextBox
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Class
        ////////////////////////////////////////////////////////////////////////////////////////// Internal

        #region 디자이너 - Designer

        /// <summary>
        /// 디자이너
        /// </summary>
        internal new class Designer : NumericTextBox.Designer
        {
            //////////////////////////////////////////////////////////////////////////////////////////////////// Method
            ////////////////////////////////////////////////////////////////////////////////////////// Protected

            #region 속성 필터 처리하기 - PostFilterProperties(propertyDictionary)

            /// <summary>
            /// 속성 필터 처리하기
            /// </summary>
            /// <param name="propertyDictionary">속성 딕셔너리</param>
            protected override void PostFilterProperties(IDictionary propertyDictionary)
            {
                propertyDictionary.Remove("DigitCountInGroup"     );
                propertyDictionary.Remove("Prefix"                );
                propertyDictionary.Remove("MaximumWholeDigitCount");

                base.PostFilterProperties(propertyDictionary);
            }

            #endregion
        }

        #endregion

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

        #region 생성자 - CurrencyTextBox()

        /// <summary>
        /// 생성자
        /// </summary>
        public CurrencyTextBox() : base(null)
        {
            this.behavior = new CurrencyBehavior(this);
        }

        #endregion
        #region 생성자 - CurrencyTextBox(behavior)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="behavior">통화 동작</param>
        public CurrencyTextBox(CurrencyBehavior behavior) : base(behavior)
        {
        }

        #endregion
    }
}

 

▶ Controls/AlphanumericTextBox.cs

using System.ComponentModel;

namespace TestProject
{
    /// <summary>
    /// 영숫자 텍스트 박스
    /// </summary>
    public class AlphanumericTextBox : TestProject.TextBox
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 동작 - Behavior

        /// <summary>
        /// 동작
        /// </summary>
        [Browsable(false)]
        public AlphanumericBehavior Behavior
        {
            get
            {
                return (AlphanumericBehavior)this.behavior;
            }
        }

        #endregion
        #region 무효한 문자 배열 - InvalidCharacterArray

        /// <summary>
        /// 무효한 문자 배열
        /// </summary>
        [Category("Behavior")]
        [Description("The array of characters considered invalid (not allowed).")]
        public char[] InvalidCharacterArray
        {
            get
            {
                return Behavior.InvalidCharacterArray;
            }
            set
            {
                Behavior.InvalidCharacterArray = value;
            }
        }

        #endregion

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

        #region 생성자 - AlphanumericTextBox()

        /// <summary>
        /// 생성자
        /// </summary>
        public AlphanumericTextBox()
        {
            this.behavior = new AlphanumericBehavior(this);
        }

        #endregion
        #region 생성자 - AlphanumericTextBox(invalidCharacterArray)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="invalidCharacterArray">무효한 문자 배열</param>
        public AlphanumericTextBox(char[] invalidCharacterArray)
        {
            this.behavior = new AlphanumericBehavior(this, invalidCharacterArray);
        }

        #endregion
        #region 생성자 - AlphanumericTextBox(invalidCharacter)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="invalidCharacter">무효한 문자</param>
        public AlphanumericTextBox(string invalidCharacter)
        {
            this.behavior = new AlphanumericBehavior(this, invalidCharacter);
        }

        #endregion
        #region 생성자 - AlphanumericTextBox(behavior)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="behavior">영숫자 동작</param>
        public AlphanumericTextBox(AlphanumericBehavior behavior) : base(behavior)
        {
        }

        #endregion
    }
}

 

▶ Controls/MaskedTextBox.cs

using System.ComponentModel;
using System.Collections;

namespace TestProject
{
    /// <summary>
    /// 마스크 텍스트 박스
    /// </summary>
    public class MaskedTextBox : TestProject.TextBox
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 동작 - Behavior

        /// <summary>
        /// 동작
        /// </summary>
        [Browsable(false)]
        public MaskedBehavior Behavior
        {
            get
            {
                return (MaskedBehavior)this.behavior;
            }
        }

        #endregion
        #region 마스크 - Mask

        /// <summary>
        /// 마스크
        /// </summary>
        /// <remarks>
        /// ##/##/#### ##:##:## - 월/일/연도 시/분/초
        /// ##/##/#### ##:##    - 월/일/연도 시/분
        /// ##/##/####          - 월/일/연도
        /// ##:##:##            - 시/분/초
        /// ##:##               - 시/분
        /// </remarks>
        [Category("Behavior")]
        [Description("The string used for formatting the characters entered into the textbox. (# = digit)")]
        public string Mask
        {
            get
            {
                return Behavior.Mask;
            }
            set
            {
                Behavior.Mask = value;
            }
        }

        #endregion
        #region 상징 리스트 - SymbolList

        /// <summary>
        /// 상징 리스트
        /// </summary>
        [Browsable(false)]
        public ArrayList SymbolList
        {
            get
            {
                return Behavior.SymbolList;
            }
        }

        #endregion
        #region 숫자 텍스트 - NumericText

        /// <summary>
        /// 숫자 텍스트
        /// </summary>
        [Browsable(false)]
        public string NumericText
        {
            get
            {
                return Behavior.NumericText;
            }
        }

        #endregion

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

        #region 생성자 - MaskedTextBox()

        /// <summary>
        /// 생성자
        /// </summary>
        public MaskedTextBox()
        {
            this.behavior = new MaskedBehavior(this);
        }

        #endregion
        #region 생성자 - MaskedTextBox(mask)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="mask">마스크</param>
        public MaskedTextBox(string mask)
        {
            this.behavior = new MaskedBehavior(this, mask);
        }

        #endregion
        #region 생성자 - MaskedTextBox(behavior)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="behavior">마스크 동작</param>
        public MaskedTextBox(MaskedBehavior behavior) : base(behavior)
        {
        }

        #endregion
    }
}

 

▶ Controls/DateTextBox.cs

using System;
using System.ComponentModel;
using System.Collections;

namespace TestProject
{
    /// <summary>
    /// 날짜 텍스트 박스
    /// </summary>
    [Designer(typeof(DateTextBox.Designer))]
    public class DateTextBox : TestProject.TextBox
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Class
        ////////////////////////////////////////////////////////////////////////////////////////// Internal

        #region 디자이너 - Designer

        /// <summary>
        /// 디자이너
        /// </summary>
        internal new class Designer : TextBox.Designer
        {
            //////////////////////////////////////////////////////////////////////////////////////////////////// Method
            ////////////////////////////////////////////////////////////////////////////////////////// Protected

            #region 속성 필터 처리하기 - PostFilterProperties(propertyDictionary)

            /// <summary>
            /// 속성 필터 처리하기
            /// </summary>
            /// <param name="propertyDictionary">속성 딕셔너리</param>
            protected override void PostFilterProperties(IDictionary propertyDictionary)
            {
                propertyDictionary.Remove("Month"             );
                propertyDictionary.Remove("Day"               );
                propertyDictionary.Remove("Year"              );
                propertyDictionary.Remove("Value"             );
                propertyDictionary.Remove("Separator"         );
                propertyDictionary.Remove("ShowDayBeforeMonth");

                base.PostFilterProperties(propertyDictionary);
            }

            #endregion
        }

        #endregion

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

        #region 동작 - Behavior

        /// <summary>
        /// 동작
        /// </summary>
        [Browsable(false)]
        public DateBehavior Behavior
        {
            get
            {
                return (DateBehavior)this.behavior;
            }
        }

        #endregion
        #region 연도 - Year

        /// <summary>
        /// 연도
        /// </summary>
        [Browsable(false)]
        public int Year
        {
            get
            {
                return Behavior.Year;
            }
            set
            {
                Behavior.Year = value;
            }
        }

        #endregion
        #region 월 - Month

        /// <summary>
        /// 월
        /// </summary>
        [Browsable(false)]
        public int Month
        {
            get
            {
                return Behavior.Month;
            }
            set
            {
                Behavior.Month = value;
            }
        }

        #endregion
        #region 일 - Day

        /// <summary>
        /// 일
        /// </summary>
        [Browsable(false)]
        public int Day
        {
            get
            {
                return Behavior.Day;
            }
            set
            {
                Behavior.Day = value;
            }
        }

        #endregion
        #region 값 - Value

        /// <summary>
        /// 값
        /// </summary>
        [Browsable(false)]
        public object Value
        {
            get
            {
                return Behavior.Value;
            }
            set
            {
                Behavior.Value = value;
            }
        }

        #endregion
        #region 범위 최소값 - RangeMinimumValue

        /// <summary>
        /// 범위 최소값
        /// </summary>
        [Category("Behavior")]
        [Description("The minimum value allowed.")]
        public DateTime RangeMinimumValue
        {
            get
            {
                return Behavior.RangeMinimumValue;
            }
            set
            {
                Behavior.RangeMinimumValue = value;
            }
        }

        #endregion
        #region 범위 최대값 - RangeMaximumValue

        /// <summary>
        /// 범위 최대값
        /// </summary>
        [Category("Behavior")]
        [Description("The maximum value allowed.")]
        public DateTime RangeMaximumValue
        {
            get
            {
                return Behavior.RangeMaximumValue;
            }
            set
            {
                Behavior.RangeMaximumValue = value;
            }
        }

        #endregion
        #region 분리자 - Separator

        /// <summary>
        /// 분리자
        /// </summary>
        [Browsable(false)]
        public char Separator
        {
            get
            {
                return Behavior.Separator;
            }
            set
            {
                Behavior.Separator = value;
            }
        }

        #endregion
        #region 월 앞 일 표시 여부 - ShowDayBeforeMonth

        /// <summary>
        /// 월 앞 일 표시 여부
        /// </summary>
        [Browsable(false)]
        public bool ShowDayBeforeMonth
        {
            get
            {
                return Behavior.ShowDayBeforeMonth;
            }
            set
            {
                Behavior.ShowDayBeforeMonth = value;
            }
        }

        #endregion

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

        #region 생성자 - DateTextBox()

        /// <summary>
        /// 생성자
        /// </summary>
        public DateTextBox()
        {
            this.behavior = new DateBehavior(this);
        }

        #endregion
        #region 생성자 - DateTextBox(behavior)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="behavior">날짜 동작</param>
        public DateTextBox(DateBehavior behavior) : base(behavior)
        {
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 날짜 설정하기 - SetDate(year, month, day)

        /// <summary>
        /// 날짜 설정하기
        /// </summary>
        /// <param name="year">연도</param>
        /// <param name="month">월</param>
        /// <param name="day">일</param>
        public void SetDate(int year, int month, int day)
        {
            Behavior.SetDate(year, month, day);
        }

        #endregion
    }
}
728x90
반응형
그리드형
Posted by 사용자 icodebroker

댓글을 달아 주세요