본문 바로가기

VB.net & WPF & C#

[WPF] number only TextBox

http://xryout.tistory.com/346

Visual C++의 Edit Control은 리소스 편집기에서 Number 속성으로 숫자입력창을 쉽게 만들 수 있었습니다.

그런데 WPF의 TextBox에는 상응하는 속성이 없더군요.

ValidationRule을 이용하여 올바른 입력을 유도하라는 의도 같습니다만 불편한건 불편한거죠.

 

http://karlhulme.wordpress.com/2007/02/15/masking-input-to-a-wpf-textbox/

검색해보니 위 링크의 해결책이 가장 많이 사용되는 것 같더군요.

하지만 다음과 같은 2가지 문제가 있었습니다.

 

1. Spacebar, Delete, Backspace 등을 처리하지 못합니다.

- 공백 문자등에 대해서는 PreviewTextInput 이벤트가 발생하지 않더군요.

2. 음수 및 소수를 처리하지 못합니다.

- 새로 입력되는 문자(또는 문자열)가 숫자인지만을 처리하는 방식이기 때문에 문자열 전체를 놓고 파악해야 하는 음수, 소수을 처리하지 못합니다.

 

그래서 다음과 같이 처리했습니다.

- 진입점은 TextChanged 이벤트 핸들러로 할당 (keyboard 입력, copy&paste, drag&drop 모두 처리 가능)

- 숫자 유효성은 문자열 전체에 대해 int, double 등의 TryParse() static 함수 사용 (int, uint, double 등의 자료형 선택으로 정수, 음수, 소수 등 입력형식/범위 제한 가능)

- 유효하지 않은 문자열이 입력된 경우 바로 이전의 유효한 문자열을 다시 할당 (문자열을 다시 할당할 경우 TextChanged 이벤트가 다시 발생한다는 점은 좀 거시기)

- 이전 문자열로 되돌릴 경우 유효한 caret 위치 및 선택상태를 유지하기 위해 SelectionChanged 이벤트 핸들러에서 SelectionStart, SelectionLength 프로퍼티값 저장

 

private string prevText;
private void text_TextChanged(object sender, TextChangedEventArgs e)
{
    TextBox textBox = sender as TextBox;

 

    double value;
    if (double.TryParse(textBox.Text, out value))
    {
        this.prevText = textBox.Text;
    }
    else
    {
        textBox.Text = this.prevText;
        textBox.SelectionLength = this.prevSelectionLength;
        textBox.SelectionStart = this.prevSelectionStart;
    }
}

int prevSelectionStart;
int prevSelectionLength;
private void text_SelectionChanged(object sender, RoutedEventArgs e)
{
    TextBox textbox = sender as TextBox;
    this.prevSelectionStart = textbox.SelectionStart;
    this.prevSelectionLength = textbox.SelectionLength;
}



-------------------------------------위의 글에서 개선.

1. 입력값이 없을때 default 0 처리

2. 입력시 값이 0이면 사라지도록.

3. [ . ] 만 입력 안되도록 막음.

4. N개의 Textbox도 가능 하도록. -> TXT_GotFocus