l 바인딩
엔진, 즉 Binding 클래스는 바인딩 원본과 바인딩 대상의
사이에서 서로의 값을 설정하거나 변화를 감시하는 역할을 수행한다.
l 바인딩
원본은 어떤 종류의 CLR 개체도 사용할 수 있으며 바인딩 원본의 바인딩 할 속성도 제한이 없다.
l 바인딩
대상은 반드시 FrameworkElement에서
파생된 클래스이어야 하고 바인딩 대상 속성은 반드시 DependencyProperty이어야 한다.
l 화살표는
바인딩의 방향을 나타내며 구성에 따라 단방향 혹은 양방향으로 연결할 수 있다.
l 바인딩에
의해 값이 변경될 때 ValueConverter가 지정되어 있을 경우 값이 적절하게 변환되어 설정된다.
바인딩은 다른 실버라이트 개체들과 마찬가지로 XAML과 코드로
선언할 수 있다.
[XAML]
<TextBlock Text="{Binding Id}" …/>
[C#]
TextBlock tb = new TextBlock();
Binding binding = new Binding("Id");
tb.SetBinding(TextBlock.TextProperty, binding);
|
[리스트 1. 데이터의 Id속성을 UI의 Text속성에 바인딩하는 코드 조각]
이렇게 Binding 개체에 의해 연결된 바인딩은 명시적으로 데이터
바인딩 할 원본 개체의 인스턴스를 설정하지 않으면 기본적으로 DataContext 속성에 설정되어 있는
데이터 개체로부터 바인딩 할 원본 속성을 찾는다. DataContext는 실버라이트의 비주얼 트리를
타고 하위 개체로 전파되므로 공통적인 데이터 바인딩을 하는 UI 집합에서 편리하게 사용할 수 있다.
바인딩의 기능과 표현식
바인딩은 단순히 데이터와 UI 엘리먼트를 연결하는 기능 외에도
다양한 바인딩 시나리오를 위한 기능이 준비되어 있다. 각각의 기능과 표현식에 대해 알아보자. 아래에 소개한 기능과 표현식의 모든 소스 코드는 [DataBindingFeatures]의
각 폴더에서 찾아 볼 수 있다.
1.
바인딩 할 원본 개체의 속성 설정
앞서 소개한 것처럼 바인딩 할 원본 개체의 속성은 Binding 클래스의 Path 속성을 사용하여 지정한다. XAML에서 바인딩 표현식을 사용할
때에는 Path지시자를 생략하고 바인딩 할 원본 개체의 속성만 지정할 수 있다.
또한 Path 속성을 아예 생략할 수도 있는데, 이 경우 바인딩 대상 속성에는 바인딩 원본 개체 그 자체가 바인딩 된다.
[XAML]
<TextBlock Text="{Binding Path=Name}" />
<!--
또는 -->
<TextBlock Text="{Binding Name }" />
<!--
또는 -->
<TextBlock Text="{Binding }" />
|
[리스트 2. 바인딩
경로를 설정하는 XAML 표현식]
2.
명시적인 데이터 원본 설정
데이터 원본은 Binding클래스의 Source 속성으로 설정할 수 있다. Source 속성을 생략할
경우 자동으로 DataContext에서 바인딩할 속성을 가져온다. 일반적인
경우 Source 속성을 생략하고 DataContext로부터
바인딩 받는 경우가 대부분이지만 때로 명시적인 DataContext가 아닌 명시적인 원본 설정이 필요할
때도 있다.
[XAML]
<TextBlock Text="{Binding Path=Id, Source={StaticResource MyProfile} }" />
|
[리스트 3. 명시적으로
바인딩 원본을 설정하는 XAML 표현식]
XAML에서 Source를
명시적으로 사용하기 위해서는 먼저 해당 엘리먼트를 포함하는 사용자 컨트롤이나 App.xaml에 반드시
바인딩할 원본을 리소스로 등록한 후 StaticResource 표현식을 사용하여 설정해야 한다. 위의 예제는 리소스로 등록된 MyResource 개체를 바인딩 원본으로
사용하여 MyResource.Id 속성을 Text 속성에
바인딩한다는 의미이다.
3.
데이터의 흐름 설정
Binding 클래스의 Mode
속성으로 원본을 대상에 어떤 방향으로 바인딩 할지 설정할 수 있다. 데이터 흐름에는 다음과
같은 세 종류가 있으며 Mode 속성이 생략 될 경우 자동으로
OneWay 방식이 선택된다.
l OneTime
최초로 바인딩 원본이 설정될 때 단 한번만 바인딩 대상을 변경하는 모드.
l OneWay
바인딩된 원본이 변경사항을 알려줄 때마다 자동으로 바인딩 대상도 변경하는 모드.
l TwoWay
바인딩 대상이 변경되었을 때 역으로 바인딩 원본도 변경하는 양방향 모드.
[XAML]
<TextBlock Text="{Binding Id, Mode=OneTime}" />
<!--
또는 -->
<TextBlock Text="{Binding Id, Mode=OneWay}" />
<!--
또는 -->
<TextBlock Text="{Binding Id, Mode=TwoWay}" />
|
[리스트 4. 바인딩
흐름을 설정하는 XAML 표현식]
단, OneWay와 TwoWay
모드가 정상적으로 동작하기 위해서는 데이터 원본 오브젝트가 반드시 다음의
INotifyPropertyChanged 인터페이스를 구현해야 한다.
4.
데이터 원본의 변경 알림
위에서 본 데이터 바인딩의 OneWay혹은 TwoWay 모드는 데이터 원본이 변경되면 자동으로 바인딩 대상도 변경되어야 한다. 이를 위해 데이터 원본 개체는 자신의 데이터가 변경될 때 바인딩 개체에 그 사실을 알려줘야 한다.
이 과정은 모든 CLR 개체에서 자동으로 되는 것이 아니라 INotifyPropertyChanged라는 인터페이스를 상속받은 개체에서 코드를 통해 명시적으로 구현을 해야
한다.
[C#]
public class Profile : INotifyPropertyChanged
{
private
string _id;
public string Id
{
get
{ return _id; }
set
{
_id = value;
FirePropertyChanged("Id");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler
PropertyChanged;
protected
void FirePropertyChanged(string propertyName)
{
if
(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
|
[리스트 5.
INotifyPropertyChanged 인터페이스를 구현하는 원본 개체의 예제]
이렇게 데이터 원본은 PropertyChanged 이벤트를 발생시키고
바인딩 엔진은 그 이벤트를 받아 바인딩 대상 속성을 변경한다.
5.
데이터 컨버팅
때로는 바인딩 원본 속성의 타입과 바인딩 대상 속성의 타입이 일치하지 않을 수도 있다. 예를 들어 TextBlock의
Text 속성에 DateTime 타입의 값을 바인딩한다면 시스템의 로캘에 따라 “18/03/2009 PM 08:09:00”과 같이 원치 않는 형식으로 바인딩되는 것을 볼 수 있다. 이 때 IValueConverter 인터페이스를 상속하는 클래스를
하나 만들고 IValueConverter 인터페이스의 Convert 메서드와 ConvertBack 메서드를 구현하면 된다. 이렇게 구현한 ValueConverter는 먼저 XAML에 리소스로 등록을 한 후 Binding 클래스의 Converter속성에 리소스를 설정하면 된다. 또한 ConverterParameter 속성을 사용하면 값을 변환할
때 옵션을 부여할 수 있다.
[XAML]
<TextBox Text="{Binding Birthday,
Mode=TwoWay,
Converter={StaticResource
DateConverter},
ConverterParameter=yyyy년 MM월 dd일}"
/>
[C#]
public class DateValueConverter : IValueConverter
{
public object Convert(object
value, Type targetType, object parameter, CultureInfo
culture)
{
// 생략…
return
…;
}
public object ConvertBack(object
value, Type targetType, object parameter, CultureInfo
culture)
{
// 생략
return
…;
}
#endregion
}
|
[리스트 6.
IValueConverter 인터페이스를 구현하는 원본 개체의 예제]
Convert 메서드는 데이터 원본에서 바인딩 대상 방향으로 설정할
때 사용되고 ConvertBack 메서드는 반대로 바인딩 대상의 변화를 데이터 원본에 설정할 때 사용된다. 참고로 앞의 코드 조각에서 볼 수 있듯이 바인딩 표현식은 보기 좋게 정리하기 위해 표현식의 각 지시자 사이에
엔터를 포함한 공백을 넣을 수 있다.
6.
데이터 유효성 검사
TwoWay 바인딩이 설정된
TextBox에서 사용자가 문자열을 입력하면 입력된 문자열이 다시 데이터 원본 속성에 설정이 된다.
이 때 기본적으로 데이터 원본 속성의 설정자에서 사용자 입력의 유효성을 검사할 수도 있고
ValueConverter를 사용하여 유효한 형태로 변환할 수도 있다. 그러나 이렇게 할
경우 사용자가 잘못된 입력을 했다는 것을 상위 UI에 알려주려면 별도의 이벤트나 메서드를 사용해야 한다. 특히 복잡한 UI를 가진 입력 폼 등의 애플리케이션은 표준적인 입력
오류를 알려주는 수단이 필요하다.
Binding 클래스는 데이터 유효성 검사를 위해 ValidatesOnExceptions 속성과
NotifyOnValidationError 속성을 지원한다. 이 두 속성을 모두 True로 설정하면 데이터 원본의 속성이 바인딩 엔진에 의해 설정 중에 발생된 예외를 잡아서 BindingValidationError 이벤트로 전달한다. BindingValidationError
이벤트는 모든 FrameworkElement가 가지고 있는 이벤트로 이벤트가 발생한 엘리먼트에서부터
시작하여 이벤트가 처리될때까지 상위 엘리먼트로 계속 라우팅되는 버블 이벤트이다.
[XAML]
<TextBox
Text="{Binding Path=Age,
NotifyOnValidationError=true,
ValidatesOnExceptions=true}" />
[C#]
public class Profile : INotifyPropertyChanged
{
private int _age;
public int Age
{
get
{ return _age; }
set
{
if
(value < 0 || value
> 150)
throw
new Exception("나이는 0~150까지만 가능합니다.");
_age = value;
FirePropertyChanged("Age");
}
}
}
// 바인딩 에러 처리
void Page_BindingValidationError(object
sender, ValidationErrorEventArgs e)
{
// 에러가 발생할 때 처리
if
(e.Action == ValidationErrorEventAction.Added)
ErrorCaption.Text =
e.Error.Exception.Message;
// 에러가 해결되었을 때 처리
else if (e.Action == ValidationErrorEventAction.Removed)
ErrorCaption.Text = "";
e.Handled = true;
}
|
[리스트 7. BindingValidationError를
이용한 데이터 유효성 검사 예제]
지금까지 실버라이트 데이터 바인딩의 원리와 중요한 기능들을 살펴보았다. 물론
이것들은 데이터 바인딩의 가장 기초적인 부분이다. 보다 효과적인 사용을 위해서는 세심한 데이터 모델
설계와 UI의 구성, 그리고 무엇보다도 디자이너와의 협업이
중요하다. 다음 글에서는 데이터 바인딩을 보다 효과적으로 사용하는 방법과 디자이너와 협업하기 위한 방법에
대해 알아보도록 하겠다.
-----------------------------