데이터 바인딩 개요

업데이트: 2008년 7월

WPF(Windows Presentation Foundation) 데이터 바인딩은 응용 프로그램에서 데이터를 표시하고 데이터와 상호 작용하는 간단하고 편리한 방법입니다. 다양한 데이터 소스에서 CLR(공용 언어 런타임) 개체 및 XML의 형태로 데이터에 요소를 바인딩할 수 있습니다. ContentControl(예: Button) 및 ItemsControl(예: ListBoxListView)에는 데이터 항목 컬렉션이나 단일 데이터 항목에 유연하게 스타일을 지정할 수 있도록 기본 제공되는 기능이 있습니다. 데이터를 기반으로 정렬, 필터 및 그룹 보기를 생성할 수 있습니다.

WPF의 데이터 바인딩 기능에는 데이터 바인딩을 지원하는 다양한 속성, 데이터의 유연한 UI 표현 및 비즈니스 논리와 UI의 명확한 분리와 같은 기존 모델보다 향상된 여러 가지 기능이 있습니다.

이 항목에서는 먼저 WPF 데이터 바인딩에 대한 핵심 개념을 살펴본 다음 Binding 클래스 및 기타 데이터 바인딩 기능을 사용하는 방법에 대해 살펴봅니다.

이 항목에는 다음 단원이 포함되어 있습니다.

  • 데이터 바인딩의 정의
  • 기본 데이터 바인딩 개념
  • 바인딩 만들기
  • 데이터 변환
  • 컬렉션에 바인딩
  • 데이터 템플릿
  • 데이터 유효성 검사
  • 디버깅 메커니즘
  • 관련 항목

데이터 바인딩의 정의

데이터 바인딩은 응용 프로그램 UI와 비즈니스 논리를 서로 연결하는 프로세스입니다. 바인딩 설정이 올바르고 데이터가 적절한 알림을 제공하는 경우에는 데이터의 값이 변경될 때 데이터에 바인딩된 요소에 변경 내용이 자동으로 반영됩니다. 또한 요소에서 데이터의 외부 표현이 변경되면 내부 데이터가 자동으로 업데이트되어 변경 내용이 반영됩니다. 예를 들어 사용자가 TextBox 요소의 값을 편집하면 해당 변경에 따라 내부 데이터 값이 자동으로 업데이트됩니다.

데이터 바인딩의 일반적인 용도는 서버 또는 로컬 구성 데이터를 폼이나 기타 UI 컨트롤에 배치하는 것입니다. WPF에서는 이 개념이 더욱 확장되어 다양한 속성을 여러 가지 데이터 소스에 바인딩할 수 있게 되었습니다. WPF에서는 요소의 종속성 속성을 CLR 개체(ADO.NET 개체 또는 웹 서비스 및 웹 속성과 연결된 개체 포함) 및 XML 데이터에 바인딩할 수 있습니다.

데이터 바인딩의 예로 데이터 바인딩 데모의 응용 프로그램 UI를 살펴보겠습니다.

데이터 바인딩 샘플 스크린 샷

위 그림은 경매 항목의 목록을 표시하는 응용 프로그램의 UI입니다. 이 응용 프로그램은 데이터 바인딩의 다음 기능을 보여 줍니다.

  • ListBox의 콘텐츠가 AuctionItem 개체의 컬렉션에 바인딩됩니다. AuctionItem 개체에는 Description, StartPrice, StartDate, Category, SpecialFeatures 등의 속성이 있습니다.

  • ListBox에 표시되는 데이터(AuctionItem 개체)는 템플릿으로 사용되어 각 항목에 대한 설명과 현재 가격을 표시합니다. 이는 DataTemplate을 사용하여 수행됩니다. 또한 각 항목의 모양은 표시되는 AuctionItemSpecialFeatures 값에 따라 달라집니다. AuctionItemSpecialFeatures 값이 Color이면 항목에 파란색 테두리가 표시됩니다. 값이 Highlight이면 항목에 주황색 테두리와 별이 표시됩니다. 데이터 템플릿에 대한 내용은 데이터 템플릿 단원에서 볼 수 있습니다.

  • 사용자는 제공된 CheckBox를 사용하여 데이터를 그룹화하거나, 필터링하거나, 정렬할 수 있습니다. 위의 이미지에서는 "Group by category" 및 "Sort by category and date" CheckBox가 선택되어 있습니다. 데이터가 제품 범주별로 그룹화되어 있으며 범주 이름은 사전순으로 정렬되어 있음을 볼 수 있습니다. 이미지에서 확인하기는 쉽지 않지만 항목은 각 범주 내에서 시작 날짜별로 정렬되어 있습니다. 이 기능은 컬렉션 뷰를 사용하여 수행됩니다. 컬렉션 뷰에 대한 내용은 컬렉션에 바인딩 단원에서 다룹니다.

  • 사용자가 항목을 선택하면 ContentControl이 선택된 항목의 세부 사항을 표시합니다. 이를 마스터-세부 시나리오라고 합니다. 이러한 형식의 바인딩 시나리오에 대한 내용은 마스터-세부 시나리오 단원에서 볼 수 있습니다.

  • StartDate 속성의 형식은 밀리초 단위의 시간까지 포함된 날짜를 반환하는 DateTime입니다. 이 응용 프로그램에서는 더 짧은 날짜 문자열을 표시하기 위해 사용자 지정 변환기를 사용합니다. 변환기에 대한 내용은 데이터 변환 단원에서 볼 수 있습니다.

사용자가 Add Product 단추를 클릭하면 다음 폼이 나타납니다.

제품 목록 추가 페이지

사용자는 폼의 필드를 편집하고, 짧은 미리 보기와 더 자세한 미리 보기 창을 사용하여 제품 목록을 미리 볼 수 있으며 submit을 클릭하여 새 제품 목록을 추가할 수 있습니다. 기존의 모든 그룹화, 필터링 및 정렬 기능이 새 항목에 적용됩니다. 이 특별한 경우에서는 위의 이미지에 입력된 항목이 Computer 범주에서 두 번째 항목으로 표시됩니다.

이 이미지에 표시되지 않은 것은 Start Date TextBox에 제공되는 유효성 검사 논리입니다. 사용자가 올바르지 않은 날짜(형식이 올바르지 않은 날짜나 지난 날짜)를 입력하면 ToolTip이 표시되고 TextBox 옆에 빨간색 느낌표가 나타납니다. 데이터 유효성 검사 단원에서는 유효성 검사 논리를 만드는 방법을 설명합니다.

위에서 개괄적으로 설명한 데이터 바인딩의 다른 기능을 살펴보기 전에 다음 단원에서는 WPF 데이터 바인딩 이해에 필수적인 기본 개념을 살펴보겠습니다.

기본 데이터 바인딩 개념

이 단원에는 다음 하위 단원이 포함되어 있습니다.

  • 데이터 흐름의 방향
  • 소스 업데이트를 트리거하는 항목

바인딩하려는 요소 및 데이터 소스의 특성에 관계없이 각 바인딩은 항상 다음 그림에 나타나는 모델을 따릅니다.

기본 데이터 바인딩 다이어그램

위 그림에서 볼 수 있듯이, 데이터 바인딩은 기본적으로 바인딩 대상과 바인딩 소스 사이의 다리 역할을 합니다. 그림에서는 다음 기본 WPF 데이터 바인딩 개념을 보여 줍니다.

  • 일반적으로 각 바인딩에는 4가지 구성 요소인 바인딩 대상 개체, 대상 속성, 바인딩 소스 및 사용할 바인딩 소스 값에 대한 경로가 있습니다. 예를 들어 TextBox의 내용을 Employee 개체의 Name 속성에 바인딩하려는 경우 대상 개체는 TextBox이고 대상 속성은 Text 속성이며 사용할 값은 Name, 소스 개체는 Employee 개체입니다.

  • 대상 속성은 종속성 속성이어야 합니다. UIElement 속성 대부분은 종속성 속성이며 읽기 전용 속성을 제외한 대부분의 종속성 속성은 기본적으로 데이터 바인딩을 지원합니다. DependencyObject 형식만 종속성 속성을 정의할 수 있으며 모든 UIElementDependencyObject에서 파생됩니다.

  • 그림에는 지정되어 있지 않지만 바인딩 소스 개체는 사용자 지정 CLR 개체로 제한되지 않습니다. WPF 데이터 바인딩은 CLR 개체와 XML 형식의 데이터를 지원합니다. 몇 가지 예제를 제공하기 위해 바인딩 소스는 UIElement, 목록 개체, ADO.NET 데이터나 웹 서비스와 연결된 CLR 개체 또는 XML 데이터가 들어 있는 XmlNode 중에 선택할 수 있습니다. 자세한 내용은 바인딩 소스 개요를 참조하십시오.

다른 SDK(소프트웨어 개발 키트) 항목을 읽을 때 바인딩을 설정하는 것은 곧 바인딩 대상 바인딩 소스에 바인딩하는 것임을 기억하십시오. 예를 들어 데이터 바인딩을 사용하여 일부 내부 XML 데이터를 ListBox에 표시하는 것은 곧 ListBox를 XML 데이터에 바인딩하는 것입니다.

바인딩을 설정하려면 Binding 개체를 사용해야 합니다. 이 항목의 나머지 부분에서는 Binding 개체의 사용법과 몇 가지 속성 및 여러 가지 관련 개념을 설명합니다.

데이터 흐름의 방향

앞의 설명과 위 그림의 화살표에서 알 수 있듯이, 바인딩의 데이터 흐름은 바인딩 대상에서 바인딩 소스로(예를 들어 사용자가 TextBox의 값을 편집하면 소스 값이 변경됨) 흐르거나 바인딩 소스가 적절한 알림을 제공하는 경우에는 바인딩 소스에서 바인딩 대상으로 흐를 수 있습니다(예를 들어 바인딩 소스가 변경되면 TextBox 내용이 업데이트됨).

사용자가 응용 프로그램에서 데이터를 변경했을 때 이 변경 내용이 소스 개체로 전파되어야 할 수 있습니다. 또는 사용자가 소스 데이터를 업데이트하지 못하도록 해야 할 수 있습니다. Binding 개체의 Mode 속성을 설정하여 이를 제어할 수 있습니다. 다음 그림에서는 여러 가지 형태의 데이터 흐름을 보여 줍니다.

데이터 바인딩 데이터 흐름

  • OneWay 바인딩을 사용하면, 소스 속성이 변경된 경우 대상 속성이 자동으로 업데이트되지만 대상 속성이 변경된 경우에는 변경 내용이 소스 속성으로 전파되지 않습니다. 이 형식의 바인딩은 바인딩되는 컨트롤이 암시적으로 읽기 전용인 경우 적합합니다. 예를 들어 주식 시세 표시기와 같은 소스에 바인딩하거나 대상 속성에 테이블의 데이터 바인딩된 배경색과 같이 변경을 위해 제공된 컨트롤 인터페이스가 없을 수 있습니다. 대상 속성의 변경 내용을 모니터링할 필요가 없는 경우 OneWay 바인딩 모드를 사용하면 TwoWay 바인딩 모드의 오버헤드를 줄일 수 있습니다.

  • TwoWay 바인딩의 경우에는 소스 속성이 변경되면 자동으로 대상 속성이 업데이트되고, 대상 속성이 변경되면 자동으로 소스 속성이 업데이트됩니다. 이 형식의 바인딩은 편집 가능한 폼이나 기타 완전 대화형 UI 시나리오에 적합합니다. 대부분의 속성은 OneWay 바인딩을 기본값으로 사용하지만 일부 종속성 속성(일반적으로 TextBoxText 속성 및 CheckBoxIsChecked 속성)은 TwoWay 바인딩을 기본값으로 사용합니다. 기본적으로 종속성 속성이 단방향으로 바인딩되는지 아니면 양방향으로 바인딩되는지를 확인하는 프로그래밍 방식은 GetMetadata를 사용하여 속성의 속성 메타데이터를 가져온 다음 BindsTwoWayByDefault 속성의 Boolean 값을 확인하는 것입니다.

  • OneWayToSourceOneWay 바인딩의 반대입니다. 즉, 대상 속성이 변경될 때 소스 속성을 업데이트합니다. 이에 대한 한 가지 예제 시나리오는 UI에서 소스 값을 다시 확인하기만 하면 되는 경우입니다.

  • 그림에는 표시되지 않았지만 OneTime 바인딩의 경우에는 소스 속성이 대상 속성을 초기화하지만 이후 변경은 전파되지 않습니다. 즉, 데이터 컨텍스트가 변경되고 있거나 데이터 컨텍스트의 개체가 변경된 경우 변경이 대상 속성에 반영된다는 것을 의미합니다. 이 형식의 바인딩은 현재 상태의 스냅숏이 사용하기에 적합하거나 데이터가 정적인 상황에서 데이터를 사용하는 경우 적합합니다. 또한 이 형식의 바인딩은 소스 속성의 값으로 대상 속성을 초기화하려고 하고 데이터 컨텍스트가 미리 알려지지 않은 경우 유용합니다. 이것은 소스 값이 변경되지 않는 경우 향상된 성능을 제공하는 보다 간단한 형식의 OneWay 바인딩입니다.

소스 변경 내용을 검색하려면(OneWayTwoWay 바인딩에 적용 가능) 소스에서 INotifyPropertyChanged와 같은 적절한 속성 변경 알림 메커니즘을 구현해야 합니다. INotifyPropertyChanged 구현에 대한 예제를 보려면 방법: 속성 변경 알림 구현을 참조하십시오.

Mode 속성 페이지에서 바인딩 모드에 대한 자세한 내용과 바인딩의 방향을 지정하는 방법에 대한 예제를 제공합니다.

소스 업데이트를 트리거하는 항목

TwoWay 또는 OneWayToSource인 바인딩은 대상 속성의 변경 내용을 수신하고 해당 변경 내용을 다시 소스로 전파합니다. 이 과정을 소스 업데이트라고 합니다. 예를 들어 TextBox의 텍스트를 편집하여 기본 소스 값을 변경할 수 있습니다. 이전 단원에서 설명한 것처럼, 데이터 흐름의 방향은 바인딩의 Mode 속성 값에 따라 결정됩니다.

하지만 텍스트를 편집하고 있을 때나 텍스트 편집을 마치고 마우스를 TextBox 외부로 움직였을 때 소스 값이 업데이트될까요? 소스 업데이트를 트리거할 항목은 바인딩의 UpdateSourceTrigger 속성에 따라 결정됩니다. 다음 그림에서 오른쪽 화살표의 점은 UpdateSourceTrigger 속성의 역할을 보여 줍니다:

UpdateSourceTrigger 다이어그램

UpdateSourceTrigger 값이 PropertyChanged이면 대상 속성이 변경되는 즉시 OneWayToSource 바인딩 또는 TwoWay 바인딩의 오른쪽 화살표가 가리키는 값이 업데이트됩니다. 하지만 UpdateSourceTrigger 값이 LostFocus이면 대상 속성이 포커스를 잃었을 때에만 해당 값이 새 값으로 업데이트됩니다.

Mode 속성과 비슷하게 여러 종속성 속성의 기본 UpdateSourceTrigger 값은 서로 다릅니다. Text 속성의 기본값은 LostFocus이지만, 대부분의 종속성 속성의 기본값은 PropertyChanged입니다. 이는 대상 속성이 변경될 때마다 소스 업데이트가 수행된다는 것을 의미합니다. 이러한 특징은 CheckBox 및 기타 간단한 컨트롤에 적합합니다. 하지만 텍스트 필드의 경우에는 키 입력이 있을 때마다 업데이트하면 성능이 떨어지고, 일반적으로 사용자가 새 값을 커밋하기 전에 백스페이스 키를 누르고 입력 오류를 수정할 수 있는 기회가 없어집니다. 이런 이유 때문에 Text 속성의 기본값은 PropertyChanged가 아닌 LostFocus입니다.

종속성 속성의 기본 UpdateSourceTrigger 값을 찾는 방법에 대해서는 UpdateSourceTrigger 속성 페이지를 참조하십시오.

다음 표에서는 TextBox를 예제로 사용하여 각 UpdateSourceTrigger 값에 대한 예제 시나리오를 제공합니다.

UpdateSourceTrigger 값

소스 값이 업데이트될 때

TextBox에 대한 예제 시나리오

LostFocus(TextBox.Text의 기본값)

TextBox 컨트롤이 포커스를 잃을 때

유효성 검사 논리와 연결된 TextBox(데이터 유효성 검사 단원 참조)

PropertyChanged

TextBox에 입력할 때

채팅방 창의 TextBox 컨트롤

Explicit

응용 프로그램에서 UpdateSource를 호출할 때

편집 가능한 폼의 TextBox 컨트롤(사용자가 제출 단추를 클릭할 때만 소스 값 업데이트)

예제를 보려면 방법: TextBox 텍스트의 소스를 업데이트하는 시점 제어를 참조하십시오.

바인딩 만들기

이 단원에는 다음 하위 단원이 포함되어 있습니다.

  • 바인딩 소스 지정
  • 값에 대한 경로 지정
  • Binding 및 BindingExpression

이전 단원에서 설명한 개념을 다시 요약하면, Binding 개체를 사용하여 바인딩을 만들며 각 바인딩에는 일반적으로 바인딩 대상, 대상 속성, 바인딩 소스 및 사용할 소스 값에 대한 경로의 네 구성 요소가 있습니다. 이 단원에서는 바인딩을 설정하는 방법을 설명합니다.

바인딩 소스 개체가 SDKSample 네임스페이스에 정의된 MyData라는 클래스인 다음 예제를 생각해 볼 수 있습니다. 설명을 위해 MyData 클래스에는 값이 "Red"로 설정되는 ColorName이라는 문자열 속성이 있습니다. 따라서 이 예제에서는 배경이 빨간색인 단추를 생성합니다.

<DockPanel
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:c="clr-namespace:SDKSample">
  <DockPanel.Resources>
    <c:MyData x:Key="myDataSource"/>
  </DockPanel.Resources>
  <DockPanel.DataContext>
    <Binding Source="{StaticResource myDataSource}"/>
  </DockPanel.DataContext>
  <Button Background="{Binding Path=ColorName}"
          Width="150" Height="30">I am bound to be RED!</Button>
</DockPanel>

바인딩 선언 구문에 대한 자세한 설명과 코드에서 바인딩을 설정하는 방법에 대한 예제를 보려면 바인딩 선언 개요를 참조하십시오.

이 예제를 기본 다이어그램에 적용한 결과 그림은 다음과 같습니다. 여기에서 Background 속성이 기본적으로 OneWay 바인딩을 지원하므로 이 예제에서는 OneWay 바인딩입니다.

데이터 바인딩 다이어그램

Background 속성의 형식이 Brush인데 ColorName 속성이 문자열 형식이어도 작동하는 이유가 궁금할 것입니다. 기본 형식 변환이 작동하기 때문이며 이에 대해서는 데이터 변환 단원에서 설명합니다.

바인딩 소스 지정

이전 예제에서는 DockPanel 요소에 DataContext 속성을 설정하여 바인딩 소스를 지정합니다. 그러면 Button은 부모 요소인 DockPanel에서 DataContext 값을 상속합니다. 바인딩 소스 개체는 바인딩의 네 가지 필수 구성 요소 중 하나입니다. 따라서 바인딩 소스 개체를 지정하지 않으면 바인딩은 아무 작업도 수행하지 않습니다.

바인딩 소스 개체를 지정하는 방법에는 몇 가지가 있습니다. 여러 속성을 같은 소스에 바인딩할 때는 부모 요소에 DataContext 속성을 사용하는 방법이 유용합니다. 하지만 개별 바인딩 선언에서 바인딩 소스를 지정하는 것이 더 적합할 경우도 있습니다. 이전 예제의 경우 DataContext 속성을 사용하는 대신 다음 예제에서처럼 단추의 바인딩 선언에 직접 Source 속성을 설정하여 바인딩 소스를 지정할 수 있습니다.

<DockPanel.Resources>
  <c:MyData x:Key="myDataSource"/>
</DockPanel.Resources>
<Button Width="150" Height="30"
        Background="{Binding Source={StaticResource myDataSource},
                             Path=ColorName}">I am bound to be RED!</Button>

요소에 직접 DataContext 속성을 설정하고, 상위에서 DataContext 값을 상속하고(첫 번째 예제의 단추에서처럼), BindingSource 속성을 설정하여 바인딩 소스를 명시적으로 지정하는 방법(이전 예제의 단추에서처럼) 이외에도, ElementName 속성 또는 RelativeSource 속성을 사용하여 바인딩 소스를 지정할 수도 있습니다. ElementName 속성은 슬라이더를 사용하여 단추 너비를 조정하는 경우처럼 응용 프로그램의 다른 요소에 바인딩할 때 유용합니다. RelativeSource 속성은 ControlTemplate 또는 Style에서 바인딩을 지정할 때 유용합니다. 자세한 내용은 방법: 바인딩 소스 지정을 참조하십시오.

값에 대한 경로 지정

바인딩 소스가 개체일 때는 Path 속성을 사용하여 바인딩에 사용할 값을 지정합니다. XML 데이터에 바인딩할 때는 XPath 속성을 사용하여 값을 지정합니다. 경우에 따라서는 데이터가 XML일 경우에도 Path 속성을 사용하는 것이 적절할 수 있습니다. 예를 들어 반환된 XmlNode(XPath 쿼리의 결과로)의 Name 속성에 액세스하려면 XPath 속성 이외에 Path 속성도 사용해야 합니다.

구문 정보와 예제에 대해서는 PathXPath 속성 페이지를 참조하십시오.

사용할 값에 대한 Path가 바인딩의 네 가지 필수 구성 요소 중 하나임을 강조했지만, 전체 개체에 바인딩하려는 시나리오에서는 사용할 값이 바인딩 소스 개체와 같습니다. 이런 경우에는 Path를 지정하지 않는 편이 적절합니다. 다음 예제를 참조하십시오.

<ListBox ItemsSource="{Binding}"
         IsSynchronizedWithCurrentItem="true"/>

위의 예제에서는 빈 바인딩 구문 {Binding}을 사용합니다. 이 경우 ListBox는 부모 DockPanel 요소에서 DataContext를 상속합니다(이 예제에는 표시되지 않음). 경로를 지정하지 않으면 기본적으로 전체 개체에 바인딩합니다. 달리 말하면, 이 예제에서는 ItemsSource 속성을 전체 개체에 바인딩하고 있으므로 경로를 비워둔 것입니다. 자세한 내용은 컬렉션에 바인딩 단원을 참조하십시오.

이 시나리오는 컬렉션에 대한 바인딩 이외에 개체의 단일 속성만이 아니라 전체 개체에 바인딩할 때도 유용합니다. 소스 개체가 문자열 형식일 때 문자열 자체에만 바인딩하려는 경우를 예로 들 수 있습니다. 다른 일반적인 시나리오는 요소를 몇 개의 속성이 있는 개체에 바인딩하려는 경우입니다.

바인딩된 대상 속성에서 데이터가 의미를 갖게 하기 위해 사용자 지정 논리를 적용해야 하는 경우가 있습니다. 사용자 지정 논리는 사용자 지정 변환기(기본 형식 변환이 없는 경우)의 형태일 수 있습니다. 변환기에 대한 자세한 내용은 데이터 변환을 참조하십시오.

Binding 및 BindingExpression

데이터 바인딩의 다른 기능 및 사용 방법을 다루기 전에 BindingExpression 클래스를 살펴보면 도움이 될 것입니다. 이전 단원에서 보았듯이 Binding 클래스는 바인딩 선언의 고급 클래스입니다. 즉, Binding 클래스는 바인딩의 특성을 지정할 수 있는 여러 속성을 제공합니다. 관련 클래스인 BindingExpression은 소스와 대상 사이의 연결을 유지 관리하는 기본 개체입니다. 바인딩에는 여러 바인딩 식에서 공유될 수 있는 모든 정보가 포함됩니다. BindingExpression은 공유할 수 없으며 Binding의 모든 인스턴스 정보를 포함하는 인스턴스 식입니다.

myDataObjectMyData 클래스의 인스턴스이고, myBinding이 소스 Binding 개체이고, MyData 클래스가 MyDataProperty라는 문자열 속성을 포함하는 정의된 클래스인 다음 예제를 예로 들 수 있습니다. 이 예제에서는 TextBlock의 인스턴스인 mytext의 텍스트 내용을 MyDataProperty에 바인딩합니다.

Dim data1 As New MyData(DateTime.Now)
Dim binding1 As New Binding("MyDataProperty")
binding1.Source = data1
Me.myText.SetBinding(TextBlock.TextProperty, binding1)
//make a new source
  MyData myDataObject = new MyData(DateTime.Now);      
  Binding myBinding = new Binding("MyDataProperty");
  myBinding.Source = myDataObject;
  myText.SetBinding(TextBlock.TextProperty, myBinding);

동일한 myBinding 개체를 사용하여 다른 바인딩을 만들 수 있습니다. 예를 들어 myBinding 개체를 사용하여 확인란의 텍스트 내용을 MyDataProperty에 바인딩할 수 있습니다. 해당 시나리오에서는 myBinding 개체를 공유하는 BindingExpression의 인스턴스가 두 개 있습니다.

BindingExpression 개체는 데이터 바인딩 개체에 대한 GetBindingExpression 호출의 반환 값을 통해 얻을 수 있습니다. 다음 항목에서는 BindingExpression 클래스의 몇 가지 사용법을 보여 줍니다.

데이터 변환

앞의 예제에서 단추의 Background 속성은 값이 "Red"인 문자열 속성에 바인딩되기 때문에 단추가 빨간색입니다. Brush 형식에 문자열 값을 Brush로 변환하는 형식 변환기가 있기 때문에 이런 식으로 작동합니다.

이 정보를 바인딩 만들기 단원의 그림에 추가하면 다이어그램은 다음과 같아집니다.

데이터 바인딩 다이어그램

하지만 바인딩 소스 개체에 문자열 형식의 속성이 아니라 Color 형식의 Color 속성이 있으면 어떻게 될까요? 이러한 경우 바인딩이 동작하려면 먼저 Color 속성 값을 Background 속성에 사용할 수 있는 무언가로 변환해야 합니다. 다음 예제에서처럼 IValueConverter 인터페이스를 구현하여 사용자 지정 변환기를 만들어야 합니다.

[ValueConversion(typeof(Color), typeof(SolidColorBrush))]
public class ColorBrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Color color = (Color)value;
        return new SolidColorBrush(color);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}

IValueConverter 참조 페이지에서 자세한 내용을 볼 수 있습니다.

이제 사용자 지정 변환기가 기본 변환 대신에 사용되며 다이어그램은 다음과 같아집니다.

데이터 바인딩 다이어그램

앞서 설명했듯이 바인딩하는 형식에 있는 형식 변환기 때문에 기본 변환을 사용할 수 있습니다. 이 동작은 대상에서 사용할 수 있는 형식 변환기에 따라 달라집니다. 확실하지 않은 경우 변환기를 직접 만들어 보십시오.

다음은 데이터 변환기를 구현하는 것이 적합한 몇 가지 일반적인 시나리오입니다.

  • 데이터를 문화권에 따라 다르게 표시해야 하는 경우. 예를 들어 특정 문화권에 사용되는 표준이나 값에 따라 통화 변환기 또는 달력 날짜/시간 변환기를 구현할 수 있습니다.

  • 사용되는 데이터를 반드시 속성의 텍스트 값으로 변경할 필요는 없지만 이미지의 소스 또는 표시 텍스트의 색이나 스타일과 같은 다른 값으로 변경해야 하는 경우. 이러한 경우 텍스트 필드를 표 셀의 Background 속성에 바인딩하는 경우처럼 적합하지 않은 것처럼 보일 수 있는 속성의 바인딩을 변환하는 방법으로 변환기를 사용할 수 있습니다.

  • 둘 이상의 컨트롤 또는 컨트롤의 여러 속성을 같은 데이터에 바인딩하는 경우. 이러한 경우 기본 바인딩은 텍스트만 표시하고 다른 바인딩은 같은 바인딩을 소스 정보로 사용하면서 특정 표시 문제를 처리할 수 있습니다.

  • 대상 속성에 바인딩 컬렉션이 있는 MultiBinding에 대해서는 아직 살펴보지 않았습니다. MultiBinding의 경우에는 사용자 지정 IMultiValueConverter를 사용하여 바인딩의 값에서 최종 값을 생성합니다. 예를 들어 빨간색, 파란색 및 녹색 값에 따라 색이 계산될 수 있으며, 이 값은 같거나 다른 바인딩 소스 개체의 값일 수 있습니다. 이에 대한 내용 및 예제를 보려면 MultiBinding 클래스 페이지를 참조하십시오.

컬렉션에 바인딩

이 단원에는 다음 하위 단원이 포함되어 있습니다.

  • 컬렉션 구현 방법
  • 컬렉션 뷰

바인딩 소스 개체는 속성에서 데이터를 포함하는 단일 개체 또는 함께 그룹화되는 경우가 많은(예: 데이터베이스에 대한 쿼리 결과) 다형성 개체의 데이터 컬렉션으로 취급될 수 있습니다. 지금까지 단일 개체에 대한 바인딩만 다뤘지만 대개는 데이터 컬렉션으로의 바인딩이 많이 사용됩니다. 예를 들어 일반적인 시나리오에서는 ListBox, ListView, TreeView 등의 ItemsControl을 사용하여 데이터 바인딩의 정의 단원에 소개된 응용 프로그램 등에서 데이터 컬렉션을 표시합니다.

이 경우에도 앞에서 소개한 기본 다이어그램이 여전히 적용됩니다. ItemsControl을 컬렉션에 바인딩하면 다이어그램은 다음과 같아집니다.

데이터 바인딩 ItemsControl 다이어그램

이 다이어그램에서 볼 수 있듯이 ItemsControl을 컬렉션 개체에 바인딩하려면 ItemsSource 속성을 사용해야 합니다. ItemsSource 속성은 ItemsControl의 내용이라고 생각할 수 있습니다. ItemsSource 속성이 OneWay 바인딩을 기본적으로 지원하기 때문에 바인딩은 OneWay라는 점에 유의하십시오.

컬렉션 구현 방법

IEnumerable 인터페이스를 구현하는 모든 컬렉션을 열거할 수 있습니다. 그러나 컬렉션에서 삽입이나 삭제를 수행할 때 UI가 자동으로 업데이트되도록 동적 바인딩을 설정하려면 컬렉션에서 INotifyCollectionChanged 인터페이스를 구현해야 합니다. 이 인터페이스는 내부 컬렉션이 변경될 때마다 발생해야 하는 이벤트를 노출합니다.

WPF에서는 INotifyCollectionChanged 인터페이스를 노출하는 데이터 컬렉션에 대한 기본 제공 구현인 ObservableCollection<T> 클래스를 제공합니다. 데이터 값을 소스 개체에서 대상으로 전송하는 것을 완전하게 지원하려면 바인딩 가능한 속성을 지원하는 컬렉션의 각 개체도 INotifyPropertyChanged 인터페이스를 구현해야 합니다. 예제를 보려면 컬렉션 바인딩 샘플을 참조하십시오. 자세한 내용은 바인딩 소스 개요를 참조하십시오.

컬렉션을 직접 구현하는 대신 ObservableCollection<T>을 사용하거나 List<T>, Collection<T>BindingList<T>를 비롯한 기존 컬렉션 클래스 중 하나를 사용하는 것이 좋습니다. 고급 시나리오에서 컬렉션을 직접 구현해야 하는 경우 인덱스에 따라 개별적으로 액세스할 수 있는 개체의 제네릭이 아닌 컬렉션을 제공하고 성능이 가장 높은 IList를 사용하는 것이 좋습니다.

컬렉션 뷰

ItemsControl을 데이터 컬렉션에 바인딩한 뒤에는 데이터를 정렬하거나, 필터링하거나, 그룹화할 수 있습니다. 이렇게 하려면 ICollectionView 인터페이스를 구현하는 클래스인 컬렉션 뷰를 사용합니다.

이 단원에는 다음 하위 단원이 포함되어 있습니다.

  • 컬렉션 뷰의 정의
  • 뷰를 만드는 방법
  • 정렬
  • 필터링
  • 그룹화
  • 현재 항목 포인터
  • 마스터-세부 바인딩 시나리오

컬렉션 뷰의 정의

컬렉션 뷰는 기본 소스 컬렉션 자체를 변경할 필요 없이 정렬, 필터 및 그룹화 쿼리를 기반으로 소스 컬렉션을 탐색하고 표시하는 데 사용할 수 있는 바인딩 소스 컬렉션의 최상위 계층입니다. 또한 컬렉션 뷰는 컬렉션의 현재 항목에 대한 포인터를 유지 관리합니다. INotifyCollectionChanged 인터페이스가 소스 컬렉션에서 구현될 경우 CollectionChanged 이벤트에서 발생되는 변경 내용은 뷰로 전파됩니다.

뷰는 기본 소스 컬렉션을 변경하지 않으므로 각 소스 컬렉션에 여러 개의 뷰를 연결하여 사용할 수 있습니다. 예를 들어 Task 개체의 컬렉션을 사용할 수 있습니다. 또한 뷰를 사용하면 동일한 데이터를 여러 가지 다른 방식으로 표시할 수 있습니다. 예를 들어, 페이지 왼쪽에 우선 순위별로 정렬된 작업을 표시하고 오른쪽에 영역별로 그룹화된 작업을 표시할 수 있습니다.

뷰를 만드는 방법

뷰를 만들고 사용하는 한 가지 방법은 뷰 개체를 직접 인스턴스화한 다음 이를 바인딩 소스로 사용하는 방법입니다. 데이터 바인딩의 정의 단원에서 소개한 데이터 바인딩 데모 응용 프로그램을 예로 들어 보겠습니다. 응용 프로그램은 ListBox가 직접 데이터 컬렉션에 바인딩하는 대신 해당 데이터 컬렉션에 대한 뷰에 바인딩하는 방식으로 구현됩니다. 다음은 데이터 바인딩 데모 응용 프로그램에서 발췌한 예제입니다. CollectionViewSource 클래스는 CollectionView에서 상속되는 클래스의 XAML(Extensible Application Markup Language) 프록시입니다. 이 예제에서는 뷰의 Source가 현재 응용 프로그램 개체의 AuctionItems 컬렉션(ObservableCollection<T> 형식)에 바인딩됩니다.

<Window.Resources>


...


<CollectionViewSource 
      Source="{Binding Source={x:Static Application.Current}, Path=AuctionItems}"   
      x:Key="listingDataView" />


...


</Window.Resources>

그런 다음 리소스 listingDataViewListBox와 같은 응용 프로그램 요소에 대한 바인딩 소스의 역할을 합니다.

<ListBox Name="Master" Grid.Row="2" Grid.ColumnSpan="3" Margin="8"
    ItemsSource="{Binding Source={StaticResource listingDataView}}">


...


</ListBox>

같은 컬렉션에 대한 다른 뷰를 만들려면 다른 CollectionViewSource 인스턴스를 만들고 다른 x:Key 이름을 지정할 수 있습니다.

다음 표에서는 기본 컬렉션 뷰로 만들어지거나 소스 컬렉션 형식을 기반으로 CollectionViewSource에서 만드는 뷰 데이터 형식을 보여 줍니다.

소스 컬렉션 형식

컬렉션 뷰 형식

설명

IEnumerable

CollectionView에 기반을 둔 내부 형식

항목을 그룹화할 수 없습니다.

IList

ListCollectionView

가장 빠릅니다.

IBindingList

BindingListCollectionView

기본 뷰 사용

컬렉션 뷰를 바인딩 소스로 지정하는 것은 컬렉션 뷰를 만들고 사용하는 다양한 방법 중 하나에 불과합니다. WPF에서는 바인딩 소스로 사용되는 모든 컬렉션에 대해 기본 컬렉션 뷰를 만듭니다. WPF에서 컬렉션에 직접 바인딩하면 컬렉션의 기본 뷰에 바인딩됩니다. 이 기본 뷰는 동일 컬렉션에 대한 모든 바인딩에서 공유하므로 바인딩된 컨트롤이나 코드 중 하나에 의해 기본 뷰가 변경되면 동일 컬렉션에 대한 모든 바인딩에 해당 변경 내용이 반영됩니다. 정렬이나 현재 항목 포인터의 변경을 예로 들 수 있으며 이에 대해서는 뒤에서 자세히 설명합니다.

기본 뷰를 가져오려면 GetDefaultView 메서드를 사용합니다. 예제를 보려면 방법: 데이터 수집의 기본 뷰 가져오기를 참조하시시오.

ADO.NET DataTable이 포함된 컬렉션 뷰

성능 향상을 위해 ADO.NET DataTable 또는 DataView 개체에 대한 컬렉션 뷰는 정렬 및 필터링을 DataView에 위임합니다. 이렇게 하면 정렬 및 필터링이 데이터 소스의 모든 컬렉션 뷰에서 공유됩니다. 각 컬렉션 뷰를 독립적으로 정렬 및 필터링하려면 각 컬렉션 뷰의 DataView 개체를 사용하여 컬렉션 뷰를 초기화합니다.

정렬

앞서 설명했듯이 뷰는 컬렉션에 정렬 순서를 적용할 수 있습니다. 기본 컬렉션에 존재하기 때문에 데이터에 적절한 기본 순서가 있거나 없을 수 있습니다. 컬렉션에 대한 뷰를 사용하면 지정한 비교 기준에 따라 기본 순서를 변경하거나 순서를 적용할 수 있습니다. 데이터의 클라이언트 기반 뷰이기 때문에 사용자는 열에 해당하는 값에 따라 표 형식 데이터의 열을 정렬할 수 있습니다. 뷰를 사용하면 기본 컬렉션을 변경하거나 컬렉션 내용을 다시 쿼리하지 않고 이렇게 사용자가 중심의 정렬을 적용할 수 있습니다. 예제를 보려면 방법: 머리글을 클릭할 때 GridView 열 정렬을 참조하십시오.

다음 예제에서는 데이터 바인딩의 정의 단원에서 소개한 응용 프로그램 UI에 있는 "Sort by category and date" CheckBox의 정렬 논리를 보여 줍니다.

private void AddSorting(object sender, RoutedEventArgs args)
{
    // This sorts the items first by Category and within each Category,
    // by StartDate. Notice that because Category is an enumeration,
    // the order of the items is the same as in the enumeration declaration
    listingDataView.SortDescriptions.Add(
        new SortDescription("Category", ListSortDirection.Ascending));
    listingDataView.SortDescriptions.Add(
        new SortDescription("StartDate", ListSortDirection.Ascending));
}

필터링

뷰는 컬렉션에 필터를 적용할 수도 있습니다. 즉, 컬렉션에 한 항목이 있어도 이 특정 뷰는 전체 컬렉션의 특정 하위 집합만 표시할 수 있습니다. 데이터에서 조건을 기준으로 필터링할 수 있습니다. 예를 들어, 데이터 바인딩의 정의 단원의 응용 프로그램에서 "Show only bargains" CheckBox에는 가격이 $25 이상인 항목을 필터링하는 논리가 들어 있습니다. 해당 CheckBox를 선택하면 다음 코드가 실행되어 ShowOnlyBargainsFilterFilter 이벤트 처리기로 설정합니다.

listingDataView.Filter += new FilterEventHandler(ShowOnlyBargainsFilter);

ShowOnlyBargainsFilter 이벤트 처리기에는 다음과 같은 구현이 있습니다.

private void ShowOnlyBargainsFilter(object sender, FilterEventArgs e)
{
    AuctionItem product = e.Item as AuctionItem;
    if (product != null)
    {
        // Filter out products with price 25 or above
        if (product.CurrentPrice < 25)
        {
            e.Accepted = true;
        }
        else
        {
            e.Accepted = false;
        }
    }
}

CollectionViewSource 대신 CollectionView 클래스 중 하나를 직접 사용하는 경우에는 Filter 속성을 사용하여 콜백을 지정합니다. 예제를 보려면 방법: 뷰에서 데이터 필터링을 참조하십시오.

그룹화

IEnumerable 컬렉션을 표시하는 내부 클래스를 제외한 모든 컬렉션 뷰는 그룹화 기능을 지원하며, 이를 통해 사용자는 컬렉션 뷰의 컬렉션을 논리 그룹으로 나눌 수 있습니다. 사용자가 그룹 목록을 제공할 경우 그룹은 명시적이며, 그룹이 데이터에 따라 동적으로 생성될 경우 그룹은 암시적입니다.

다음 예제에서는 "Group by category" CheckBox의 논리를 보여 줍니다.

// This groups the items in the view by the property "Category"
PropertyGroupDescription groupDescription = new PropertyGroupDescription();
groupDescription.PropertyName = "Category";
listingDataView.GroupDescriptions.Add(groupDescription);

다른 그룹화 예제를 보려면 방법: GridView를 구현하는 ListView의 항목 그룹화를 참조하십시오.

현재 항목 포인터

뷰는 현재 항목의 개념도 지원합니다. 컬렉션 뷰에서 개체를 탐색할 수 있습니다. 탐색할 때 항목 포인터를 이동하여 컬렉션의 특정 위치에 있는 개체를 검색할 수 있습니다. 예제를 보려면 방법: 데이터 수집 뷰의 개체 탐색을 참조하십시오.

WPF에서는 뷰(지정한 뷰 또는 컬렉션의 기본 뷰)를 사용해서만 컬렉션에 바인딩하므로 컬렉션에 대한 모든 바인딩에는 현재 항목 포인터가 있습니다. 뷰에 바인딩하는 경우 Path 값에서 슬래시("/") 문자를 사용하여 뷰의 현재 항목을 지정합니다. 다음 예제에서는 데이터 컨텍스트가 컬렉션 뷰입니다. 첫 번째 줄은 컬렉션에 바인딩되고, 두 번째 줄은 컬렉션의 현재 항목에 바인딩되며, 세 번째 줄은 컬렉션에 있는 현재 항목의 Description 속성에 바인딩됩니다.

<Button Content="{Binding }" />
<Button Content="{Binding Path=/}" />
<Button Content="{Binding Path=/Description}" /> 

또한 컬렉션 계층을 이동하기 위해 슬래시와 속성 구문을 누적시킬 수 있습니다. 다음 예제에서는 Offices라는 컬렉션의 현재 항목에 바인딩합니다. 이 컬렉션은 소스 컬렉션에 있는 현재 항목의 속성입니다.

<Button Content="{Binding /Offices/}" />

현재 항목 포인터는 컬렉션에 적용되는 정렬이나 필터링으로 인해 변경될 수 있습니다. 정렬이 적용되는 경우에는 선택한 마지막 항목에 현재 항목 포인터가 유지되지만 해당 항목 주위에서 컬렉션 뷰가 재구성됩니다. 선택한 항목이 이전에는 목록의 시작 부분에 있었지만 지금은 중간 부분에 있을 수 있습니다. 필터링이 적용되는 경우에는 필터링 후 선택 영역이 뷰에 남아 있으면 선택한 항목이 유지됩니다. 그렇지 않으면 현재 항목 포인터가 필터링된 컬렉션 뷰의 첫 번째 항목으로 설정됩니다.

마스터-세부 바인딩 시나리오

현재 항목의 개념은 컬렉션 항목의 탐색에 유용할 뿐만 아니라 마스터-세부 바인딩 시나리오에도 유용합니다. 데이터 바인딩의 정의 단원에서 소개한 응용 프로그램 UI를 다시 예로 들어 보겠습니다. 이 응용 프로그램에서는 ListBox에서의 선택한 내용에 따라 ContentControl에 표시되는 내용이 결정됩니다. 이를 다른 방법으로 구현하면, ListBox 항목을 선택했을 때 선택한 항목의 세부 사항을 ContentControl에 표시할 수 있습니다.

둘 이상의 컨트롤을 같은 뷰에 바인딩하면 마스터-세부 시나리오를 간단하게 구현할 수 있습니다. 데이터 바인딩 데모의 다음 예제에서는 데이터 바인딩의 정의 단원의 응용 프로그램 UI에 표시되는 ListBoxContentControl의 태그를 보여 줍니다.

<ListBox Name="Master" Grid.Row="2" Grid.ColumnSpan="3" Margin="8"
    ItemsSource="{Binding Source={StaticResource listingDataView}}">


...


</ListBox>


...


<ContentControl Name="Detail" Grid.Row="3" Grid.ColumnSpan="3" 
        Content="{Binding Source={StaticResource listingDataView}}" 
        ContentTemplate="{StaticResource detailsProductListingTemplate}" 
        Margin="9,0,0,0"/>

두 컨트롤 모두 같은 소스인 listingDataView 정적 리소스(뷰를 만드는 방법 단원에서 이 리소스의 정의 참조)에 바인딩됩니다. singleton 개체(이 경우 ContentControl)가 컬렉션 뷰에 바인딩되면 자동으로 뷰의 CurrentItem에 바인딩되기 때문에 이런 방식으로 동작합니다. CollectionViewSource 개체는 자동으로 통화와 선택 항목을 동기화합니다. 목록 컨트롤이 이 예제에서처럼 CollectionViewSource 개체에 바인딩되지 않는 경우에는 IsSynchronizedWithCurrentItem 속성을 true로 설정해야 이렇게 동작합니다.

다른 예제를 보려면 방법: 선택에 따라 수집 및 표시 정보에 바인딩방법: 계층적 데이터에 마스터-세부 패턴 사용을 참조하십시오.

위의 예제에서는 템플릿을 사용하는 것을 알 수 있습니다. 사실 템플릿(ContentControl에서 명시적으로 사용된 템플릿과 ListBox에서 암시적으로 사용하는 템플릿)을 사용하지 않으면 데이터가 원하는 대로 표시되지 않습니다. 이제 다음 단원에서 데이터 템플릿을 살펴보겠습니다.

데이터 템플릿

데이터 템플릿을 사용하지 않으면 데이터 바인딩의 정의 단원의 응용 프로그램 UI는 다음과 같이 표시됩니다.

데이터 템플릿을 사용하지 않는 데이터 바인딩 데모

이전 단원의 예제에서 볼 수 있듯이 ListBox 컨트롤과 ContentControl은 모두 AuctionItem의 전체 컬렉션 개체(더 구체적으로는 컬렉션 개체에 대한 뷰)에 바인딩됩니다. 데이터 컬렉션을 표시하는 방법에 대한 특정한 지침이 없으면 ListBox에는 기본 컬렉션에 있는 각 개체의 문자열 표현이 표시되고 ContentControl에는 바인딩된 개체의 문자열 표현이 표시됩니다.

이 문제를 해결하기 위해 응용 프로그램에서는 DataTemplate을 정의합니다. 이전 단원의 예제에서처럼 ContentControl에서는 detailsProductListingTemplate DataTemplate을 명시적으로 사용합니다. ListBox 컨트롤은 컬렉션에서 AuctionItem 개체를 표시할 때 다음 DataTemplate을 암시적으로 사용합니다.

<DataTemplate DataType="{x:Type src:AuctionItem}">
    <Border BorderThickness="1" BorderBrush="Gray"
            Padding="7" Name="border" Margin="3" Width="500">
        <Grid>
          <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
          </Grid.RowDefinitions>
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="20"/>
            <ColumnDefinition Width="86"/>
            <ColumnDefinition Width="*"/>
          </Grid.ColumnDefinitions>

            <Polygon Grid.Row="0" Grid.Column="0" Grid.RowSpan="4"
                     Fill="Yellow" Stroke="Black" StrokeThickness="1"
                     StrokeLineJoin="Round" Width="20" Height="20"
                     Stretch="Fill"
                     Points="9,2 11,7 17,7 12,10 14,15 9,12 4,15 6,10 1,7 7,7"
                     Visibility="Hidden" Name="star"/>

            <TextBlock Grid.Row="0" Grid.Column="1" Margin="0,0,8,0"
                       Name="descriptionTitle"
                       Style="{StaticResource smallTitleStyle}">Description:</TextBlock>
            <TextBlock Name="DescriptionDTDataType" Grid.Row="0" Grid.Column="2" 
                Text="{Binding Path=Description}" 
                Style="{StaticResource textStyleTextBlock}"/>

            <TextBlock Grid.Row="1" Grid.Column="1" Margin="0,0,8,0"
                       Name="currentPriceTitle"
                       Style="{StaticResource smallTitleStyle}">Current Price:</TextBlock>
            <StackPanel Grid.Row="1" Grid.Column="2" Orientation="Horizontal">
                <TextBlock Text="$" Style="{StaticResource textStyleTextBlock}"/>
                <TextBlock Name="CurrentPriceDTDataType" 
                    Text="{Binding Path=CurrentPrice}" 
                    Style="{StaticResource textStyleTextBlock}"/>
            </StackPanel>
        </Grid>
    </Border>
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding Path=SpecialFeatures}">
            <DataTrigger.Value>
                <src:SpecialFeatures>Color</src:SpecialFeatures>
            </DataTrigger.Value>
          <DataTrigger.Setters>
            <Setter Property="BorderBrush" Value="DodgerBlue" TargetName="border" />
            <Setter Property="Foreground" Value="Navy" TargetName="descriptionTitle" />
            <Setter Property="Foreground" Value="Navy" TargetName="currentPriceTitle" />
            <Setter Property="BorderThickness" Value="3" TargetName="border" />
            <Setter Property="Padding" Value="5" TargetName="border" />
          </DataTrigger.Setters>
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=SpecialFeatures}">
            <DataTrigger.Value>
                <src:SpecialFeatures>Highlight</src:SpecialFeatures>
            </DataTrigger.Value>
            <Setter Property="BorderBrush" Value="Orange" TargetName="border" />
            <Setter Property="Foreground" Value="Navy" TargetName="descriptionTitle" />
            <Setter Property="Foreground" Value="Navy" TargetName="currentPriceTitle" />
            <Setter Property="Visibility" Value="Visible" TargetName="star" />
            <Setter Property="BorderThickness" Value="3" TargetName="border" />
            <Setter Property="Padding" Value="5" TargetName="border" />
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

이 두 개의 DataTemplate을 사용하면 UI가 데이터 바인딩의 정의 단원에서 볼 수 있는 것과 같이 표시됩니다. 이 스크린 샷에서 볼 수 있듯이, DataTemplate을 사용하면 데이터를 컨트롤에 넣을 수 있을 뿐만 아니라 데이터를 시각적으로 뛰어나게 표현할 수도 있습니다. 예를 들어 위의 DataTemplate에서는 DataTrigger가 사용되어 SpecialFeatures 값이 HighLightAuctionItem에 오렌지색 테두리와 별이 표시됩니다.

데이터 템플릿에 대한 자세한 내용은 데이터 템플릿 개요를 참조하십시오.

데이터 유효성 검사

이 단원에는 다음 하위 단원이 포함되어 있습니다.

  • 유효성 검사 규칙을 바인딩과 연결
  • 시각적 피드백 제공
  • 유효성 검사 프로세스

사용자 입력을 받는 대부분의 응용 프로그램에는 사용자가 올바른 정보를 입력했는지 확인하기 위한 유효성 검사 논리가 필요합니다. 유효성 검사는 형식, 범위, 서식 또는 기타 응용 프로그램별 요구 사항을 기반으로 할 수 있습니다. 이 단원에서는 WPF에서 데이터 유효성 검사가 작동하는 방식을 살펴봅니다.

유효성 검사 규칙을 바인딩과 연결

WPF 데이터 바인딩 모델을 사용하면 ValidationRulesBinding 개체와 연결할 수 있습니다. 예를 들어, 다음은 데이터 바인딩의 정의 단원의 Add Product Listing "Start Price" TextBox에 대한 XAML입니다.

<TextBox Name="StartPriceEntryForm" Grid.Row="2" Grid.Column="1"
    Style="{StaticResource textStyleTextBox}" Margin="8,5,0,5">
  <TextBox.Text>
    <Binding Path="StartPrice" UpdateSourceTrigger="PropertyChanged">
      <Binding.ValidationRules>
        <ExceptionValidationRule />
      </Binding.ValidationRules>
    </Binding>
  </TextBox.Text>
</TextBox>

ValidationRules 속성은 ValidationRule 개체의 컬렉션을 사용합니다. ExceptionValidationRule은 바인딩 소스 속성의 업데이트 도중 throw된 예외를 검사하는 기본 제공 ValidationRule입니다. 이 예제에서 바인딩 소스 속성은 StartPrice(정수 형식)이며 대상 속성은 TextBox.Text입니다. 사용자가 정수로 변환할 수 없는 값을 입력하면 예외가 throw되어 바인딩이 유효하지 않은 것으로 표시됩니다.

ValidationRule 클래스에서 파생하고 Validate 메서드를 구현하여 유효성 검사 규칙을 직접 만들 수도 있습니다. 다음 예제에서는 데이터 바인딩의 정의 단원의 Add Product Listing "Start Date" TextBox에 사용되는 규칙을 보여 줍니다.

class FutureDateRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        DateTime date;
        try
        {
            date = DateTime.Parse(value.ToString());
        }
        catch (FormatException)
        {
            return new ValidationResult(false, "Value is not a valid date.");
        }
        if (DateTime.Now.Date > date)
        {
            return new ValidationResult(false, "Please enter a date in the future.");
        }
        else
        {
            return ValidationResult.ValidResult;
        }
    }
}

다음 예제에서처럼 StartDateEntryForm TextBox에서는 이 FutureDateRule을 사용합니다.

<TextBox Name="StartDateEntryForm" Grid.Row="3" Grid.Column="1" 
    Validation.ErrorTemplate="{StaticResource validationTemplate}" 
    Style="{StaticResource textStyleTextBox}" Margin="8,5,0,5">
    <TextBox.Text>
        <Binding Path="StartDate" UpdateSourceTrigger="PropertyChanged" 
            Converter="{StaticResource dateConverter}" >
            <Binding.ValidationRules>
                <src:FutureDateRule />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

UpdateSourceTrigger 값이 PropertyChanged이기 때문에 바인딩 엔진은 키 입력이 있을 때마다 소스 값을 업데이트합니다. 즉, 키 입력이 있을 때마다 ValidationRules 컬렉션의 모든 규칙을 검사합니다. 이에 대해서는 유효성 검사 프로세스 단원에서 자세히 다룹니다.

시각적 피드백 제공

사용자가 잘못된 값을 입력하는 경우 응용 프로그램 UI에서 오류에 대한 몇 가지 피드백을 제공할 수 있습니다. 이러한 피드백을 제공하는 한 가지 방법은 Validation.ErrorTemplate 연결된 속성을 사용자 지정 ControlTemplate으로 설정하는 것입니다. 앞의 소단원에서 볼 수 있듯이 StartDateEntryForm TextBox에서는 validationTemplate이라는 ErrorTemplate을 사용합니다. 다음 예제에서는 validationTemplate의 정의를 보여 줍니다.

<ControlTemplate x:Key="validationTemplate">
  <DockPanel>
    <TextBlock Foreground="Red" FontSize="20">!</TextBlock>
    <AdornedElementPlaceholder/>
  </DockPanel>
</ControlTemplate>

AdornedElementPlaceholder 요소는 표시되는 컨트롤의 위치를 지정합니다.

ToolTip을 사용하여 오류 메시지를 표시할 수도 있습니다. StartDateEntryFormStartPriceEntryForm TextBox 모두 오류 메시지를 표시하는 ToolTip을 만드는 스타일 textStyleTextBox를 사용합니다. 다음 예제에서는 textStyleTextBox의 정의를 보여 줍니다. 바인딩된 요소의 속성에서 하나 이상의 바인딩에 오류가 있을 때 연결된 속성 Validation.HasError는 true입니다.

<Style x:Key="textStyleTextBox" TargetType="TextBox">
  <Setter Property="Foreground" Value="#333333" />
  <Setter Property="MaxLength" Value="40" />
  <Setter Property="Width" Value="392" />
  <Style.Triggers>
    <Trigger Property="Validation.HasError" Value="true">
      <Setter Property="ToolTip"
        Value="{Binding RelativeSource={RelativeSource Self},
                        Path=(Validation.Errors)[0].ErrorContent}"/>
    </Trigger>
  </Style.Triggers>
</Style>

사용자 지정 ErrorTemplateToolTip을 사용하면 유효성 검사 오류가 발생했을 때 StartDateEntryForm TextBox이 다음과 같이 표시됩니다.

데이터 바인딩 유효성 검사 오류

Binding에 유효성 검사 규칙이 연결되어 있지만 바인딩된 컨트롤에 ErrorTemplate을 지정하지 않으면 유효성 검사 오류가 있을 때 기본 ErrorTemplate이 사용되어 사용자에게 알립니다. 기본 ErrorTemplate은 표시기(Adorner) 계층에 빨간색 테두리를 정의하는 컨트롤 템플릿입니다. 기본 ErrorTemplateToolTip을 사용하면 유효성 검사 오류가 있을 때 StartPriceEntryForm TextBox의 UI는 다음과 같이 표시됩니다.

데이터 바인딩 유효성 검사 오류

대화 상자에 있는 모든 컨트롤의 유효성을 검사하기 위한 논리를 제공하는 방법에 대한 예제를 보려면 대화 상자 개요의 사용자 지정 대화 상자 단원을 참조하십시오.

유효성 검사 프로세스

유효성 검사는 대개 대상의 값이 바인딩 소스 속성으로 전송될 때 수행됩니다. 이는 TwoWayOneWayToSource 바인딩에서 발생합니다. 소스 업데이트를 트리거하는 항목 단원에서 설명한 것처럼 소스 업데이트가 수행되도록 하는 요소는 UpdateSourceTrigger 속성의 값에 따라 달라집니다.

다음은 유효성 검사 프로세스에 대한 설명입니다. 이 과정에서 언제라도 유효성 검사 오류나 다른 유형의 오류가 발생하면 프로세스가 중단됩니다.

  1. 바인딩 엔진에서는 해당 Binding에 대해 ValidationStepRawProposedValue로 설정된 사용자 지정 ValidationRule 개체가 정의되어 있는지 확인하고, 있는 경우 해당 개체 중 하나에서 오류가 발생하거나 모든 개체가 통과할 때까지 각 ValidationRuleValidate 메서드를 호출합니다.

  2. 그런 다음 바인딩 엔진에서 변환기를 호출합니다(있는 경우).

  3. 변환기가 성공하면 바인딩 엔진에서는 해당 Binding에 대해 ValidationStepConvertedProposedValue로 설정된 사용자 지정 ValidationRule 개체가 정의되어 있는지 확인하고, 있는 경우 해당 개체 중 하나에서 오류가 발생하거나 모든 개체가 통과할 때까지 ValidationStepConvertedProposedValue로 설정된 각 ValidationRule에 대해 Validate 메서드를 호출합니다.

  4. 바인딩 엔진에서 소스 속성을 설정합니다.

  5. 바인딩 엔진에서는 해당 Binding에 대해 ValidationStepUpdatedValue로 설정된 사용자 지정 ValidationRule 개체가 정의되어 있는지 확인하고, 있는 경우 해당 개체 중 하나에서 오류가 발생하거나 모든 개체가 통과할 때까지 각 ValidationStepUpdatedValue로 설정된 각 ValidationRule에 대해 Validate 메서드를 호출합니다.

  6. 바인딩 엔진에서는 해당 Binding에 대해 ValidationStepCommittedValue로 설정된 사용자 지정 ValidationRule 개체가 정의되어 있는지 확인하고, 있는 경우 해당 개체 중 하나에서 오류가 발생하거나 모든 개체가 통과할 때까지 각 ValidationStepCommittedValue로 설정된 각 ValidationRule에 대해 Validate 메서드를 호출합니다.

ValidationRule이 이 프로세스를 통과하지 못하면 바인딩 엔진에서는 ValidationError 개체를 만들어 바인딩된 요소의 Validation.Errors 컬렉션에 추가합니다. 바인딩 엔진은 지정된 단계에서 ValidationRule 개체를 실행하기 전에 해당 단계 동안 바인딩된 요소의 Validation.Errors 연결된 속성에 추가된 모든 ValidationError를 제거합니다. 예를 들어, ValidationStepUpdatedValue로 설정된 ValidationRule이 실패하는 경우 다음 번 유효성 검사 프로세스가 발생할 때 바인딩 엔진에서는 해당 ValidationError를 즉시 제거한 후 ValidationStepUpdatedValue로 설정된 ValidationRule을 호출합니다.

Validation.Errors가 비어 있지 않으면 요소의 Validation.HasError 연결된 속성은 true로 설정됩니다. 또한 BindingNotifyOnValidationError 속성이 true로 설정되는 경우 바인딩 엔진에서는 요소에 대해 Validation.Error 연결된 이벤트를 발생시킵니다.

대상에서 소스로 또는 소스에서 대상으로 유효한 값을 전송하면 Validation.Errors연결된 속성이 지워집니다.

바인딩에 연결된 ExceptionValidationRule이 있고 바인딩 엔진에서 소스를 설정할 때 예외가 throw되는 경우 바인딩 엔진은 UpdateSourceExceptionFilter가 있는지 확인합니다. UpdateSourceExceptionFilter 콜백을 사용하여 예외 처리를 위한 사용자 지정 처리기를 제공할 수 있습니다. BindingUpdateSourceExceptionFilter가 지정되지 않은 경우 바인딩 엔진은 예외가 있는 ValidationError를 만들어 바인딩된 요소의 Validation.Errors 컬렉션에 추가합니다.

디버깅 메커니즘

연결된 속성 PresentationTraceSources.TraceLevel을 바인딩 관련 개체에 설정하여 특정 바인딩의 상태 정보를 받을 수 있습니다.

참고 항목

작업

방법: LINQ 쿼리 결과에 바인딩

데이터 바인딩 데모

개념

Windows Presentation Foundation 버전 3.5의 새로운 기능

성능 최적화: 데이터 바인딩

참조

DataErrorValidationRule

기타 리소스

데이터 바인딩 샘플

데이터 바인딩 방법 항목

변경 기록

날짜

변경 내용

이유

2008년 7월

서비스 팩 1의 변경 내용을 반영하기 위해 유효성 검사 프로세스 단원이 업데이트되었습니다.

SP1 기능 변경