WPF(Windows Presentation Foundation)는 강력한 사용자 인터페이스를 손쉽게 구현할 수 있도록 지원하며, 특히 뛰어난 데이터 바인딩 기능을 제공합니다. WinForms나 ASP.NET의 데이터 바인딩과 유사한 점도 있지만, WPF는 XAML 기반의 선언적 바인딩과 코드 비하인드 방식, 또는 이 둘의 조합을 통해 더욱 유연하고 강력한 데이터 바인딩을 가능하게 합니다. 컨트롤의 속성, 공용 속성, XML, 또는 일반 객체 등 다양한 대상을 바인딩할 수 있으며, 이는 WinForms나 ASP.NET 대비 더욱 빠르고 효율적인 데이터 관리 방식을 제공합니다.
데이터 바인딩의 기본 원리
WPF에서 데이터 바인딩은 '바인딩 대상(Binding Target)'과 '데이터 원본(Data Source)' 두 가지 핵심 요소로 구성됩니다. 바인딩 대상은 DependencyProperty를 상속받는 모든 속성 또는 컨트롤이 될 수 있으며, 예를 들어 TextBox 컨트롤의 Text 속성이 이에 해당합니다. 데이터 원본은 다른 컨트롤의 속성, 객체 인스턴스, XAML 요소, ADO.NET DataSet, 또는 XML 데이터 등이 될 수 있습니다. Microsoft는 XML 데이터 바인딩을 위한 XmlDataProvider와 객체 바인딩을 위한 ObjectDataProvider와 같은 보조 클래스를 제공하여 개발 편의성을 높였습니다.
WPF 데이터 바인딩의 가장 큰 특징은 {Binding ...} 구문을 사용하여 UI와 데이터 간의 연결을 XAML에서 선언적으로 정의할 수 있다는 점입니다. 이 Binding 객체는 UI 컨트롤의 속성과 백그라운드 데이터 간의 연동을 담당하며, 프런트엔드와 백엔드 간의 느슨한 결합을 가능하게 합니다.
WPF 바인딩 엔진은 Binding 객체로부터 다음 정보를 활용합니다:
- 원본 객체와 대상 객체
- 데이터 흐름의 방향 (예:
Binding.Mode속성으로 지정) - 값 변환기 (
IValueConverter인터페이스를 구현한 클래스의 인스턴스로Converter속성 지정)
WinForms나 ASP.NET과 비교했을 때 WPF 바인딩 방식은 다음과 같은 주요 차이점을 가집니다.
-
XAML을 통한 선언적 결합:
Binding은 데이터의 다리 역할을 하며, 한쪽 끝은Binding의 원본이고 다른 한쪽은Binding의 대상입니다. 데이터가 시작되는 곳이 원본이며, 데이터가 도달하는 곳이 대상입니다. 일반적으로Binding원본은 비즈니스 로직 계층의 객체이고,Binding대상은 UI 계층의 컨트롤 객체입니다. 이 구조를 통해 데이터는Binding을 통해 UI 계층으로 전달되어 사용자에게 시각적으로 표현되며, 이는 "데이터 기반 UI"를 구현하는 핵심 메커니즘이 됩니다. -
Binding.Mode속성: 데이터 흐름 방향을 제어하는 중요한 속성입니다.멤버 이름 설명 Default 바인딩 대상 속성의 기본 Mode값을 사용합니다. 대부분의 종속성 속성은OneWay바인딩을 기본으로 하지만, 텍스트 상자나 체크박스 같은 사용자 편집 가능한 컨트롤의 속성은TwoWay바인딩이 기본값입니다. 특정DependencyProperty의 기본값이OneWay인지TwoWay인지 확인하려면GetMetadata를 사용하여 속성 메타데이터를 가져온 후BindsTwoWayByDefault속성을 확인합니다.OneTime 애플리케이션 시작 시 또는 데이터 컨텍스트가 변경될 때 바인딩 대상을 한 번만 업데이트합니다. 현재 상태의 스냅샷으로 충분하거나 데이터 상태가 정적인 경우에 적합합니다. OneWay바인딩의 간소화된 형태로, 원본 값이 자주 변경되지 않는 경우 성능상 이점을 제공합니다.OneWay 바인딩 원본(Source)이 변경될 때 바인딩 대상(Target) 속성을 업데이트합니다. 바인딩된 컨트롤이 본질적으로 읽기 전용인 경우에 적합합니다. 예를 들어, 주식 시세와 같은 원본에 바인딩할 수 있습니다. TwoWay바인딩의 오버헤드를 피하고자 할 때 유용합니다.OneWayToSource 대상 속성이 변경될 때 원본 속성을 업데이트합니다. TwoWay 원본 속성 또는 대상 속성 중 어느 한쪽이 변경되면 자동으로 다른 쪽을 업데이트합니다. 편집 가능한 폼이나 완전히 상호작용하는 UI 시나리오에 적합합니다. -
UpdateSourceTrigger속성: 사용자가 UI에 입력한 데이터가 언제 데이터 원본을 업데이트할지 결정하는 속성입니다.멤버 이름 설명 Default 바인딩 대상 속성의 기본 UpdateSourceTrigger값을 사용합니다. 대부분의 종속성 속성 기본값은PropertyChanged이지만,Text속성의 기본값은LostFocus입니다. 특정DependencyProperty의 기본값을 확인하려면GetMetadata를 사용하여 속성 메타데이터를 가져온 후DefaultUpdateSourceTrigger속성을 확인합니다.Explicit UpdateSource메서드가 명시적으로 호출될 때만 바인딩 원본을 업데이트합니다.LostFocus 바인딩 대상 요소가 포커스를 잃을 때 바인딩 원본을 업데이트합니다. PropertyChanged 바인딩 대상 속성이 변경될 때 즉시 바인딩 원본을 업데이트합니다. 다음은
UpdateSourceTrigger를Explicit으로 설정하는 예시입니다. 이 경우,TextBox의 내용이 변경되어도UpdateSource메서드를 명시적으로 호출하기 전까지는 데이터 원본이 업데이트되지 않습니다.<TextBox x:Name="productNameInput" Text="{Binding Path=ProductName, UpdateSourceTrigger=Explicit}" />
간단한 데이터 바인딩 예제
이제 ListBox에서 선택된 항목의 내용을 TextBlock에 표시하는 간단한 데이터 바인딩 예제를 살펴보겠습니다.
먼저, ListBox에 여러 ListBoxItem을 추가하여 선택 가능한 목록을 구성합니다.
다음으로, 두 번째 TextBlock의 Text 속성을 ListBox의 선택 항목과 바인딩합니다. Binding 구문에서 ElementName 속성은 TextBlock의 Text 속성이 바인딩될 컨트롤의 이름을 지정합니다. Path 속성은 ListBox 요소 중 어떤 속성에 바인딩할지를 나타냅니다. 이 경우 SelectedItem.Content를 통해 선택된 ListBoxItem의 Content 값을 가져오도록 설정합니다.
<Window x:Class="WpfAppApp.DataDisplayWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="데이터 바인딩 예제" Height="400" Width="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="10">
<TextBlock Width="250" Height="25" Text="항목 선택:" TextWrapping="Wrap" FontWeight="Bold"/>
<ListBox x:Name="itemSelectionList" Width="250" Height="80" Margin="0,5,0,0">
<ListBoxItem Content="사과"/>
<ListBoxItem Content="바나나"/>
<ListBoxItem Content="체리"/>
<ListBoxItem Content="딸기"/>
<ListBoxItem Content="오렌지"/>
<ListBoxItem Content="포도"/>
<ListBoxItem Content="키위"/>
</ListBox>
<TextBlock Width="250" Height="25" Text="선택된 항목:" Margin="0,15,0,0" FontWeight="Bold"/>
<TextBlock Width="250" Height="25" Text="{Binding ElementName=itemSelectionList, Path=SelectedItem.Content}"
Background="#EEEEEE" Padding="5" VerticalAlignment="Center">
</TextBlock>
</StackPanel>
</Grid>
</Window>