프로그래밍이야기

[ #WPF ] Custom Control (TextBox)

푸르맨 2022. 1. 15. 01:57

Custom Control의 소개

WPF에서 유용하게 사용하는 Custom Control 입니다.

자기가 원하는 바대로 Windows Control을 만들 수 있는 건 예전 MFC에서는 상상하기 어려웠습니다.

강력한 기능이지만, 생소한 기능이라 자주 헷갈릴 수 있는데요.

 

WPF에서 Custom이라고 하면, 보통 두 가지를 혼용해서 말하는 것입니다.

첫번째는 아래 그림과 같이 여러 Control을 묶는 방식입니다.

 

TextBox Control + ComboBox Control + CheckBox Control

 

Xaml 코드 일부입니다. UserControl 안에 여러 Control들을 그룹화하여 사용가능합니다.

두번째는 직접 Control을 만드는 방식입니다.

File New-> CustomContrl을 생성하는 순서로 만들 수 있습니다.

이 부분 아래에서 좀 더 자세히 설명 드리겠습니다.

 

Custom Control의 기초 튜토리얼

1. 튜토리얼포인트 예제 
- 출처 : https://www.tutorialspoint.com/wpf/wpf_custom_controls.htm 

2. 구분 
- UserControl을 활용한 CustomControl 생성 방식  
    + 용도: Layout 잡기 편하도록 
- 기존 Control(예: TextBox, Button 등)을 상속받아 CustomControl을 생성하는 방식  
    + 용도 : 기존 Control에서 제공하지 않는 입력 방식을 만들기 위해 

 

Custom Control 대한 예제  

1. TextBox 확장
 - 출처 : https://www.codeproject.com/Questions/878679/WPF-Custom-TextBox-with-Decimal-Formatting 

 

 - 해당 코드는 첨부파일로 올려놓았습니다.

CustomControl_Test.zip
0.01MB

 - 아래 출처에서 다운로드 받은 코드인데, 이해하기가 쉽습니다.

 

class TextBoxEx:TextBox 
{ 

    public string ActualText 
    { 
        get { return (string)GetValue(ActualTextProperty); } 
        set { SetValue(ActualTextProperty, value); } 
    } 

// Using a DependencyProperty as the backing store for ActualText.  This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty ActualTextProperty = 
        DependencyProperty.Register("ActualText", typeof(string), typeof(TextBoxEx), new PropertyMetadata(string.Empty, OnActualTextChanged)); 

private static void OnActualTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
        TextBox tx = d as TextBox; 
        tx.Text = (string)e.NewValue; 
        string str = tx.Text;             
        double dbl = Convert.ToDouble(str); 
        str = string.Format("{0:0.###}", dbl); 
        tx.Text = str; 
    } 

public TextBoxEx() 
    { 
        this.GotFocus += TextBoxEx_GotFocus; 
        this.LostFocus += TextBoxEx_LostFocus; 
        this.PreviewTextInput += TextBoxEx_PreviewTextInput; 
    } 

void TextBoxEx_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e) 
    { 
        decimal d; 
        if(!decimal.TryParse(e.Text,out d)) 
        { 
            e.Handled = true; 
        } 
    }         

void TextBoxEx_LostFocus(object sender, System.Windows.RoutedEventArgs e) 
    { 
        ConvertText(); 
    } 

void TextBoxEx_GotFocus(object sender, System.Windows.RoutedEventArgs e) 
    { 
        this.Text = ActualText; 
    } 

private void ConvertText() 
    { 
        string str = this.Text; 
        ActualText = str; 
        double dbl = Convert.ToDouble(str); 
        str = string.Format("{0:0.###}", dbl); 
        this.Text = str; 
    } 
}

 

Custom Control 실제 적용시 나타난 어려움  

- 실수 입력 검사 (Regex 사용) : 121.2121.121은 처리가 어려움 
- Return 또는 Enter, Esc키에 대한 예외처리 (이부분은 처리 완료) 

public class TextExControl : TextBox 

{ 

static TextExControl() 

{ 

DefaultStyleKeyProperty.OverrideMetadata(typeof(TextExControl), 

new FrameworkPropertyMetadata(typeof(TextExControl))); 

} 

 

private static readonly Regex _regex = new Regex("[^0-9.-]+"); //regex that matches disallowed text 

 

public string ActualText 

{ 

get { return (string)GetValue(ActualTextProperty); } 

set { SetValue(ActualTextProperty, value); } 

} 

 

public static readonly DependencyProperty ActualTextProperty = 

DependencyProperty.Register("ActualText", typeof(string), typeof(TextExControl), new PropertyMetadata(string.Empty, OnActualTextChanged)); 

 

private static void OnActualTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 

{ 

TextBox tx = d as TextBox; 

tx.Text = (string)e.NewValue; 

string str = tx.Text; 

double dbl = Convert.ToDouble(str);  

str = string.Format("{0:0.###}", dbl); 

str += " %"; 

tx.Text = str; 

} 

 

public TextExControl() 

{ 

this.GotFocus += TextBoxEx_GotFocus; 

this.LostFocus += TextBoxEx_LostFocus; 

this.PreviewTextInput += TextBoxEx_PreviewTextInput; 

} 

 

void TextBoxEx_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e) 

{ 

bool bRtn = _regex.IsMatch(e.Text.ToString()); 

if (bRtn == true) 

{ 

if(e.Text.ToString() != "\r") 

e.Handled = true; 

}  

//double d; 

//if (!double.TryParse(e.Text, out d)) 

// e.Handled = true; 

} 

 

void TextBoxEx_LostFocus(object sender, System.Windows.RoutedEventArgs e) 

{ 

ConvertText(); 

} 

 

void TextBoxEx_GotFocus(object sender, System.Windows.RoutedEventArgs e) 

{ 

RevertText(); 

} 

 

private void RevertText() 

{ 

this.Text = ActualText; 

} 

 

private void ConvertText() 

{ 

ActualText = this.Text; 

} 

 

}

 

출처