삽질의 현장/- .NET

#109_닷넷(.NET)_ WPF_ 다중 UI요소 데이터 바인딩 (Binding)

shovelman 2015. 11. 29. 12:31


안녕하세요 삽잡이입니다.


지난 시간부터 WPF의 데이터 바인딩에 대해서 알아보고 있습니다.



바인딩을 할 때에는 단일 요소와 바인딩 할 수도 있지만,

ListBox와 같이 Collection과도 바인딩을 할 수 있습니다.


ListBox는 여러개의 데이터를 한꺼번에 보여주는 UI 입니다.

TextBox의 데이터 원본은 객체이지만,

ListBox의 데이터 원본은 객체들의 Collection이 되겠지요.

실질적으로 ListBox 자체가 

여러개의 아이템을 화면에 보여주고자 해서 만들어 졌기 때문에,

Collection과 바인딩 되는 것이 맞습니다.





따라서, ListBox와 같이 다중 요소를 가진 UI와 데이터 바인딩을 할 때에는,

컬렉션 내에 각각 객체들이 Sync를 이루도록 해줘야겠지요.

만약, 컬렉션이 세개의 객체를 가지고 있다면,

이 객체들이 자동적으로 Sync가 되도록 해줘야될 필요성이 있습니다.


즉, 지금부터는 다중 요소 UI에 대한 바인딩을 생각해보려고합니다.


바인딩은 무조건! 속성 대 속성으로 바인딩 된다고 했습니다.

단일 객체를 ListBox에 넣기는 어색하겠지요...

그런데, 객체를 여러개 가지고 있는 컬렉션은

단일 UI 요소에 보여달라 할 수 있습니다.

컬렉션에 있는 객체 중에 하나만 보여줘도 되기 때문입니다.


다중 요소 UI와 데이터 바인딩을 하기 위해서

ObservableCollection<T> 형식을 제공해줍니다.

해당 형식의 컬렉션은 바인딩에서 사용하는 컬렉션으로써,

일반 컬렉션을 사용할 때와 달리 Data 원본에서 변화가 있을 시 

알려주는 기능을 가지고 있습니다.


이전에는 데이터 원본을 지정하는데 객체를 지정했었습니다.

자... 그런데 이제는 DataContext에 Collection 객체를 지정해주면 됩니다.



아무튼... Collection과 바인딩 할 때에는

단일 요소의 경우 UI와 0번째 인덱스의 객체가 바인딩 되고,

다중 요소의 경우 UI와 Collection이 바인딩된다고 볼 수 있습니다.



Default로 Collection의 0번째 인덱스가 

단일 요소 UI와 바인딩이 되는 이유는 View라는 녀석이 있기 때문입니다.

View는 원하는 형태의 임시 객체를 만들어준다는 개념으로 생각하시면 되는데...


View라는 녀석은 CurrentItem이라는 멤버가 있습니다.

해당 멤버가 Default로 0번이 선택되어 있기 때문에 가능한 일이지요.


사실, 컬렉션 데이터 원본은

바인딩 될 때에 원본과 바인딩 되는 것이 아니라,

컬렉션의 VIew와 바인딩 되는 것입니다.


그러면 예상이 될 수 있겠지만,

CurrentItem이 0의 값이 아닌 다른 값으로 지정되어있다면,

단일 UI의 바인딩 원본 또한 바뀌겠지요.


참고로, View의 핵심적인 멤버인 

CurrentItem을 변경시키기 위해서는 View를 얻어야겠지요.

이때 View를 얻기 위해 GetFamilyView() 메서드를 사용하게 됩니다.



해당 예시는 People이라는 바인딩된 형식에 설치된 

VIew의 참조를 얻는 것입니다.

이 참조를 인터페이스로 변환한 것이고,

해당 인터페이스가 ICollectionView인 것이지요.



아무튼....




바인딩 원본을 선택한 것입니다.

맨 위에 XAML코드에서 보여드렸던 코드인데,

ListBox는 바인딩 하는 것이 아니라,

ListBox가 가지고 있는 Item들의 소스가 바인딩 되어지는 것이죠.

즉, 내부적으로 바인딩이 이루어질 것이라고 지정한 것입니다.


ItemSource에는 Binding만 해두는 것입니다.

단일 요소 UI와 바인딩할 때와 분명 다른 문법입니다.

그렇게 되면, ListBox가 다수의 Item을 가지고 있으니 

각각의 바인딩 될 대상을 찾기위해 부모 요소를 계속 찾아다니며 

DataContext가 설정되어있는 곳과 이야기 하게 됩니다.



ListBox를 선택하게 됬을 때, 

단일 요소 UI에 선택된 데이터 원본을 보여주고 싶다면?!



데이터 바인딩은 원본 데이터와 바인딩 되는 것이 아니라 View와 바인딩 됩니다.

View가 데이터 원본이기 떄문에,

ListBox에서 변경을 하게 되면, 원소를 지정하도록 옵션을 줄 수 있습니다.

바로, IsSynchronizedWithCurrentItem 이라는 속성입니다.

해당 속성을 True로 해주게 된다면, CurrentItem과 동기화가 됩니다.



자... 지금까지 배운 내용을 정리해볼까요?

컬렉션이 변경됬다면 변경된 사실을 알려주는

ObservableCollection<T> 형식을 알아봤습니다.


해당 클래스는 컬렉션이 변경되었다는 사실을 관찰합니다.

컬렉션의 원소가 추가되었거나, 변경되었거나 등등...

즉, 컬렉션에 대한 정보가 변경이 되면 이벤트를 발생시켜주는 것이죠.

결과적으로 UI는 바인딩을 다시 시도하게 되지요.


바인딩의 기본은 Sync입니다.

지금까지 UI의 내용물이 바뀌었을 때 원본 데이터에 써지는 과정을 알아봤습니다.

그렇다면, 반대는 어떻게 될까요?

데이터가 바뀌면 UI에 업데이트 시키려면 어떻게 하냐 이겁니다.


데이터를 변경하게되면, 

자동적으로 UI에 적용이 되도록 하는데에는 

사실, INotifyPropertyChanged 인터페이스가 존재해서 가능해진 것입니다.


즉, 해당 인터페이스를 구현하게 되면,

데이터가 바뀌었을 때 UI에게 알려주는 것이죠.



예제를 통해 간략하게 알아봅시다.


속성이 변경되었다면 사실을 알려주겠다는 인터페이스가

INotifyPropertyChanged 입니다.


해당 인터페이스에는 PropertyChanged라는 이벤트가 있지요.

Delegate는 필드이기때문에 정의 시 오류가 발생하겠지만 이벤트는 아니죠.


Nickname이라는 속성이 변경됬다는 사실을 

바인딩 된 UI에게 알려주고 싶다면, 

INotifyPropertyChanged 인터페이스를 구현하면 됩니다.

즉, PropertyChanged 이벤트를 정의하고 

속성이 바뀔때마다 알려달라고 정의한 것입니다.


사실, 이벤트의 클라이언트는 UI쪽 바인딩 엔진입니다.

이벤트 핸들러를 등록해주는 클라이언트가 바로 UI쪽 바인딩 엔진이라는 것입니다.

바인딩 엔진이라는 UI 녀석이 이벤트를 자동적으로(?) 등록해주는 것이지요.


아무튼... 데이터가 변경되는 것 일뿐

사실, 이벤트에 의해 UI가 알도록 해줘야하는데

바로, INotifyPropertyChanged 의 약속을 지켜줌으로써 알려주게 됩니다.



이번 시간은 다중 UI 요소를 데이터 바인딩하는 방법에 대해서 공부했습니다.

다음시간에 뵙겠습니다.

이상 삽잡이였습니다!


<참고 : Programming WPF : 사용자 경험(UX)을 바꾸는 기술>