원하시는 부분이 Send 버튼을 눌렀을 때, Send 버튼 좌측에 위치한 메시지를 입력하는 텍스트 박스를 비우고자 하시는 게 맞나요?
맞다는 가정 하에 아래 내용을 적습니다.
INotifyPropertyChanged는 무엇인가?
INotifyPropertyChanged는 이름 그대로 속성이 변경되었음을 알리는 기능을 구현합니다. INotifyPropertyChanged 인터페이스를 구현하는 객체는 속성 값이 변경될 때 발생하는 PropertyChanged라는 이벤트를 가지며, 외부에서 이 이벤트를 구독해 속성 값이 변경될 때마다 알림을 받을 수 있습니다.
WPF의 데이터 바인딩에서 INotifyPropertyChanged의 역할
WPF에서는 데이터 바인딩 시, PropertyChanged 이벤트를 가져와 구독하는 작업이 수행됩니다. 즉 PropertyChanged가 발생할 때 EventArgs로 변경된 속성의 이름을 받고, 변경된 속성의 값을 가져와 해당 속성과 바인딩된 DependencyProperty에 반영하는 것입니다.
- 참고: INotifyPropertyChanged 인터페이스를 구현하지 않더라도 데이터 바인딩 자체는 작동합니다. 다만 강한 참조로 동작하므로 속성 값이 변경되더라도 업데이트에 문제가 있고, 이전 게시물에서 언급한 것처럼 메모리 누수 문제가 있습니다.
샘플 코드에서 메시지 박스가 업데이트되는 과정
작성자님께서 올리신 소스에서 메시지 박스(TextBox의 Text 속성)에 바인딩된 속성은 msg(msg1)이므로, TextBox의 Text 속성의 값은 msg 속성의 값을, msg 속성은 필드 변수 _txtInput의 값을 따라가며, msg 속성이 변경되었다는 PropertyChanged 이벤트가 발생할 때마다 업데이트가 발생합니다. 즉 아래와 같은 절차로 동작합니다.
- _txtInput 값 변경
- 업데이트를 원하는 시점(BtnSendAll_Clilck)에 PropertyChanged 이벤트를 발생시킴(변경 속성 이름: msg)
- msg의 Binding Target(TextBox.Text)에서 msg의 값을 확인하기 위해 msg의 getter 호출
- getter에서 _txtInput 값 반환
- Binding Target(TextBox.Text)에서 _txtInput 값을 반영
일반적으로는, 첨부하신 샘플 코드처럼 필드(_txtInput)의 값을 변경하고 해당 필드를 참조하는 속성(msg)에 대한 PropertyChanged 이벤트를 발생하는 메소드(NotifyPropertyChanged(“msg1”))를 호출하는 번거로운 방법보다는, 필드는 단지 속성의 getter setter 구현을 위한 장치 정도로만 이용하고 속성의 setter에서 값 변경과 PropertyChanged 이벤트 발생 메소드를 순차적으로 호출함으로써 이벤트를 발생시키는 방법을 즐겨 사용합니다. 절차는 다음과 같습니다.
- msg 속성에 값 할당(msg = string.Empty 등)
- msg setter 호출
- _txtInput 값 변경
- msg에 대한 PropertyChanged 이벤트 발생
- msg의 Binding Target(TextBox.Text)에서 msg의 값을 확인하기 위해 msg의 getter 호출
- getter에서 _txtInput 값 반환
- Binding Target(TextBox.Text)에서 _txtInput 값을 반영
처음에 업데이트가 안 된 이유
- Binding Source인 msg 속성의 값이 변경되지 않아서
- msg 속성에 대한 PropertyChanged 이벤트가 호출되지 않아서
msg의 값이 null인지, empty인지 확인하는 과정은 그다지 중요하지 않습니다. msg 속성의 값이 변경되어야(정확히는 setter가 호출되어야) PropertyChanged 이벤트가 발생하고, 바인딩된 TextBox에서 속성 값 변경을 감지해 변경 부분을 업데이트 할 텐데, setter가 호출되지 않으니 업데이트 역시 되지 않는 거죠. 두 번째 코드에서는 BtnSendAll_Clilck 메소드에서 msg1 = string.Empty ← 요 라인을 통해 msg1의 setter가 호출되어 속성 값(정확히는 getter에서 참조하는 _txtInput 필드의 값)도 변경되고, PropertyChanged 이벤트를 호출함으로써 속성 값 변경도 알리니까 원하시는 부분이 구현된 것이구요.
결론
- 첫 번째 샘플코드에서 메시지 박스가 비워지지 않은 것은 메시지 박스에 바인딩된 msg 속성 값이 변경되지도 않았고, msg 속성이 변경되었음을 알리는 PropertyChanged 이벤트가 발생하지도 않아서 그렇다.
- 두 번째 샘플코드에서는 BtnSendAll_Clilck 메소드 내에서 msg1 속성에 값을 할당하기도 했고, 할당 과정에서 PropertyChanged 이벤트가 발생하기도 해서 View에 반영된 것이다.
- 데이터 바인딩 시에는 속성 값이 변경되었는지를 알리는 기능을 구현해야 하고, 그 방법은 가급적(메모리 누수를 감안하면 사실상 반강제로) INotifyPropertyChanged 인터페이스를 구현함으로써 달성해야 한다.
- 엔터 키 입력 시 전송 관련 부분은 wpf keydown event 등의 키워드로 검색해 보시면 금방 나올 것 같네요. 엄격한 MVVM 패턴 적용이 아니라면 코드 비하인드를 적절히 이용하는 선에서 어렵지 않게 구현 가능할 것으로 보입니다.