데이터 바인딩 개요(WPF .NET)Data binding overview (WPF .NET)

WPF(Windows Presentation Foundation)의 데이터 바인딩은 앱이 데이터를 제공하고 상호 작용할 수 있는 간단하고 일관된 방법을 제공합니다.Data binding in Windows Presentation Foundation (WPF) provides a simple and consistent way for apps to present and interact with data. 다양한 데이터 소스에서 .NET 개체 및 XML의 형식으로 데이터에 요소를 바인딩할 수 있습니다.Elements can be bound to data from a variety of data sources in the form of .NET objects and XML. 모든 ContentControl(예: Button) 및 모든 ItemsControl(예: ListBoxListView)에는 단일 데이터 항목이나 데이터 항목 수집의 스타일을 유연하게 지정할 수 있는 기본 제공 기능이 있습니다.Any ContentControl such as Button and any ItemsControl, such as ListBox and ListView, have built-in functionality to enable flexible styling of single data items or collections of data items. 데이터를 기반으로 정렬, 필터 및 그룹 보기를 생성할 수 있습니다.Sort, filter, and group views can be generated on top of the data.

WPF의 데이터 바인딩 기능은 광범위한 속성을 통한 기본적인 데이터 바인딩 지원, 데이터의 유연한 UI 표현 및 UI와 비즈니스 논리의 분명한 분리와 같은 기존 모델에 비해 여러 가지 이점이 있습니다.The data binding functionality in WPF has several advantages over traditional models, including inherent support for data binding by a broad range of properties, flexible UI representation of data, and clean separation of business logic from UI.

이 문서에서는 먼저 WPF 데이터 바인딩의 기초 개념을 살펴본 다음, Binding 클래스 및 기타 데이터 바인딩 기능을 사용하는 방법을 다룹니다.This article first discusses concepts fundamental to WPF data binding and then covers the usage of the Binding class and other features of data binding.

중요

.NET 5(및 .NET Core)에 관한 데스크톱 가이드 설명서는 제작 중입니다.The Desktop Guide documentation for .NET 5 (and .NET Core) is under construction.

데이터 바인딩이란?What is data binding?

데이터 바인딩은 앱 UI와 해당 UI가 표시하는 데이터를 연결하는 프로세스입니다.Data binding is the process that establishes a connection between the app UI and the data it displays. 바인딩 설정이 올바르고 데이터가 적절한 알림을 제공하는 경우 데이터 값이 변경될 때 데이터에 바인딩된 요소에 변경 사항이 자동으로 반영됩니다.If the binding has the correct settings and the data provides the proper notifications, when the data changes its value, the elements that are bound to the data reflect changes automatically. 또한 요소에서 데이터의 외부 표현이 변경되면 내부 데이터가 자동으로 업데이트되어 변경 내용이 반영될 수 있습니다.Data binding can also mean that if an outer representation of the data in an element changes, then the underlying data can be automatically updated to reflect the change. 예를 들어 사용자가 TextBox 요소의 값을 편집하면 내부 데이터 값이 자동으로 업데이트되어 해당 변경 내용이 반영됩니다.For example, if the user edits the value in a TextBox element, the underlying data value is automatically updated to reflect that change.

데이터 바인딩은 일반적으로 서버 또는 로컬 구성 데이터를 양식이나 기타 UI 컨트롤에 배치하는 데 사용됩니다.A typical use of data binding is to place server or local configuration data into forms or other UI controls. WPF에서 이 개념은 광범위한 속성을 다양한 데이터 소스에 바인딩하는 기능을 포함하도록 확장됩니다.In WPF, this concept is expanded to include binding a broad range of properties to a variety of data sources. WPF에서 요소의 종속성 속성은 .NET 개체(ADO.NET 개체 또는 웹 서비스와 웹 속성에 연결된 개체 포함) 및 XML 데이터에 바인딩될 수 있습니다.In WPF, dependency properties of elements can be bound to .NET objects (including ADO.NET objects or objects associated with Web Services and Web properties) and XML data.

데이터 바인딩의 예는 경매 항목을 표시하는 Data binding demo(데이터 바인딩 데모)에서 다음 앱 UI를 살펴봅니다.For an example of data binding, take a look at the following app UI from the Data Binding Demo, which displays a list of auction items.

데이터 바인딩 샘플 스크린샷Data binding sample screenshot

앱은 데이터 바인딩의 다음 기능을 보여 줍니다.The app demonstrates the following features of data binding:

  • ListBox의 콘텐츠는 AuctionItem 개체 컬렉션에 바인딩됩니다.The content of the ListBox is bound to a collection of AuctionItem objects. AuctionItem 개체에는 Description, StartPrice, StartDate, Category, SpecialFeatures 등의 속성이 있습니다.An AuctionItem object has properties such as Description, StartPrice, StartDate, Category, SpecialFeatures, and so on.

  • ListBox에 표시된 데이터(AuctionItem 개체)는 각 항목에 관한 설명과 현재 위치가 표시되도록 템플릿으로 만들어집니다.The data (AuctionItem objects) displayed in the ListBox is templated so that the description and the current price are shown for each item. 템플릿은 DataTemplate을 사용하여 만듭니다.The template is created by using a DataTemplate. 또한 각 항목의 모양은 표시되는 AuctionItemSpecialFeatures 값에 따라 달라집니다.In addition, the appearance of each item depends on the SpecialFeatures value of the AuctionItem being displayed. AuctionItemSpecialFeatures 값이 Color 이면 항목에는 파란색 테두리가 포함됩니다.If the SpecialFeatures value of the AuctionItem is Color, the item has a blue border. Highlight 값이면 항목에는 주황색 테두리와 별모양이 포함됩니다.If the value is Highlight, the item has an orange border and a star. 데이터 템플릿 섹션에서는 데이터 템플릿을 살펴봅니다.The Data Templating section provides information about data templating.

  • 사용자는 제공된 CheckBoxes를 사용하여 데이터를 그룹화, 필터링 또는 정렬할 수 있습니다.The user can group, filter, or sort the data using the CheckBoxes provided. 위 이미지에는 Group by categorySort by category and date CheckBoxes가 선택되어 있습니다.In the image above, the Group by category and Sort by category and date CheckBoxes are selected. 데이터가 제품 범주에 따라 그룹화되고 범주 이름이 사전순으로 표시되어 있음을 알 수 있습니다.You may have noticed that the data is grouped based on the category of the product, and the category name is in alphabetical order. 그림에서 확인하기는 어렵지만 항목은 각 범주 내에서 시작 날짜별로 정렬됩니다.It is difficult to notice from the image but the items are also sorted by the start date within each category. 정렬에는 ‘컬렉션 뷰’가 사용됩니다.Sorting is done using a collection view. 컬렉션에 바인딩 섹션에서는 컬렉션 뷰를 살펴봅니다.The Binding to collections section discusses collection views.

  • 사용자가 항목을 선택하면 ContentControl은 선택한 항목의 세부 정보를 표시합니다.When the user selects an item, the ContentControl displays the details of the selected item. 이 환경을 ‘마스터-세부 시나리오’라고 합니다.This experience is called the Master-detail scenario. 마스터-세부 시나리오 섹션에서는 이 바인딩 유형을 살펴봅니다.The Master-detail scenario section provides information about this type of binding.

  • StartDate 속성 형식은 밀리초까지 시간이 포함된 날짜를 반환하는 DateTime입니다.The type of the StartDate property is DateTime, which returns a date that includes the time to the millisecond. 이 앱에는 더 짧은 날짜 문자열이 표시되도록 사용자 지정 변환기가 사용되었습니다.In this app, a custom converter has been used so that a shorter date string is displayed. 데이터 변환 섹션에서는 변환기를 살펴봅니다.The Data conversion section provides information about converters.

사용자가 Add Product 단추를 클릭하면 다음 양식이 표시됩니다.When the user selects the Add Product button, the following form comes up.

Add Product Listing 페이지Add Product Listing page

사용자는 양식에 있는 필드를 편집하고, 간단한 미리 보기 및 자세한 미리 보기 창을 사용하여 제품 목록을 미리 보고, Submit을 선택하여 새 제품 목록을 추가할 수 있습니다.The user can edit the fields in the form, preview the product listing using the short or detailed preview panes, and select Submit to add the new product listing. 기존 그룹화, 필터링 및 정렬 설정이 새 항목에 적용됩니다.Any existing grouping, filtering and sorting settings will apply to the new entry. 이 경우 위 그림에 입력된 항목은 Computer 범주에서 두 번째 항목으로 표시됩니다.In this particular case, the item entered in the above image will be displayed as the second item within the Computer category.

Start Date TextBox에 제공된 유효성 검사 논리는 이 이미지에 표시되지 않습니다.Not shown in this image is the validation logic provided in the Start Date TextBox. 사용자가 잘못된 날짜(형식이 잘못되거나 지난 날짜)를 입력하면 ToolTip이 표시되고 TextBox 옆에 빨간색 느낌표가 나타납니다.If the user enters an invalid date (invalid formatting or a past date), the user will be notified with a ToolTip and a red exclamation point next to the TextBox. 데이터 유효성 검사 섹션에서는 유효성 검사 논리를 만드는 방법을 설명합니다.The Data Validation section discusses how to create validation logic.

위에서 간략히 설명한 데이터 바인딩의 다른 기능을 살펴보기 전에 먼저 WPF 데이터 바인딩 이해에 필수적인 기본 개념을 설명합니다.Before going into the different features of data binding outlined above, we will first discuss the fundamental concepts that are critical to understanding WPF data binding.

기본 데이터 바인딩 개념Basic data binding concepts

바인딩할 요소 및 데이터 소스의 특성에 관계없이 각 바인딩은 항상 다음 그림에 나와 있는 모델을 따릅니다.Regardless of what element you are binding and the nature of your data source, each binding always follows the model illustrated by the following figure.

기본 데이터 바인딩 모델을 보여 주는 다이어그램.

그림과 같이 데이터 바인딩은 기본적으로 바인딩 대상과 바인딩 소스를 연결합니다.As the figure shows, data binding is essentially the bridge between your binding target and your binding source. 그림에서는 다음 기본 WPF 데이터 바인딩 개념을 보여 줍니다.The figure demonstrates the following fundamental WPF data binding concepts:

  • 일반적으로 각 바인딩에는 다음 네 가지 구성 요소가 있습니다.Typically, each binding has four components:

    • 바인딩 대상 개체.A binding target object.
    • 대상 속성.A target property.
    • 바인딩 소스.A binding source.
    • 사용할 바인딩 소스에 있는 값 경로.A path to the value in the binding source to use.

    예를 들어 TextBox의 콘텐츠를 Employee.Name 속성에 바인딩하려면 대상 개체는 TextBox이고, 대상 속성은 Text 속성이고, 사용할 값은 Name 이고, 소스 개체는 Employee 개체입니다.For example, if you want to bind the content of a TextBox to the Employee.Name property, your target object is the TextBox, the target property is the Text property, the value to use is Name, and the source object is the Employee object.

  • 대상 속성은 종속성 속성이어야 합니다.The target property must be a dependency property. 대부분 UIElement 속성은 종속성 속성이고 읽기 전용 속성을 제외한 대부분 종속성 속성은 기본적으로 데이터 바인딩을 지원합니다.Most UIElement properties are dependency properties, and most dependency properties, except read-only ones, support data binding by default. DependencyObject에서 파생된 형식만 종속성 속성을 정의할 수 있으며 모든 UIElement 형식은 DependencyObject에서 파생됩니다.(Only types derived from DependencyObject can define dependency properties; and all UIElement types derive from DependencyObject.)

  • 그림에는 표시되지 않았지만 바인딩 소스 개체는 사용자 지정 .NET 개체로 제한되지 않습니다.Although not shown in the figure, it should be noted that the binding source object is not restricted to being a custom .NET object. WPF 데이터 바인딩은 .NET 개체 및 XML 형식의 데이터를 지원합니다.WPF data binding supports data in the form of .NET objects and XML. 예를 들어 바인딩 소스는 UIElement, 목록 개체, ADO.NET 개체, Web Services 개체 또는 XML 데이터가 포함된 XmlNode일 수 있습니다.To provide some examples, your binding source may be a UIElement, any list object, an ADO.NET or Web Services object, or an XmlNode that contains your XML data. 자세한 내용은 바인딩 소스 개요를 참조하세요.For more information, see Binding sources overview.

바인딩을 설정하고 있다면 바인딩 소스’에’ 바인딩 대상을 바인딩하고 있다는 것을 기억하세요.It is important to remember that when you are establishing a binding, you are binding a binding target to a binding source. 예를 들어 데이터 바인딩을 사용하여 몇몇 기본 XML 데이터를 ListBox에 표시하고 있다면 XML 데이터에 ListBox를 바인딩하는 것입니다.For example, if you are displaying some underlying XML data in a ListBox using data binding, you are binding your ListBox to the XML data.

바인딩을 설정하려면 Binding 개체를 사용합니다.To establish a binding, you use the Binding object. 이 문서의 나머지 부분에서는 Binding 개체와 연결된 다양한 개념과 개체의 일부 속성 및 사용법을 살펴봅니다.The rest of this article discusses many of the concepts associated with and some of the properties and usage of the Binding object.

데이터 흐름 방향Direction of the data flow

이전 그림에서 화살표가 가리키는 대로 바인딩의 데이터 흐름은 바인딩 대상에서 바인딩 소스로 이동하거나(예: 사용자가 TextBox를 편집하면 소스 값이 변경됨), 바인딩 소스가 적절한 알림을 제공할 경우 바인딩 소스에서 바인딩 대상으로 이동합니다(예: 바인딩 소스가 변경되면 TextBox 콘텐츠가 업데이트됨).As indicated by the arrow in the previous figure, the data flow of a binding can go from the binding target to the binding source (for example, the source value changes when a user edits the value of a TextBox) and/or from the binding source to the binding target (for example, your TextBox content is updated with changes in the binding source) if the binding source provides the proper notifications.

앱에서 사용자가 데이터를 변경하고 다시 소스 개체에 전파할 수 있도록 해야 할 수 있습니다.You may want your app to enable users to change the data and propagate it back to the source object. 또는 사용자가 소스 데이터를 업데이트할 수 없도록 해야 할 수 있습니다.Or you may not want to enable users to update the source data. Binding.Mode를 설정하여 데이터 흐름을 제어할 수 있습니다.You can control the flow of data by setting the Binding.Mode.

이 그림은 다양한 유형의 데이터 흐름을 보여 줍니다.This figure illustrates the different types of data flow:

데이터 바인딩 데이터 흐름Data binding data flow

  • OneWay 바인딩을 사용하면 소스 속성이 변경될 경우 대상 속성이 자동으로 업데이트되지만 대상 속성이 변경될 경우 변경 내용이 다시 소스 속성으로 전파되지 않습니다.OneWay binding causes changes to the source property to automatically update the target property, but changes to the target property are not propagated back to the source property. 이 바인딩 유형은 바인드되는 컨트롤이 암시적으로 읽기 전용인 경우에 적합합니다.This type of binding is appropriate if the control being bound is implicitly read-only. 예를 들어 주식 시세표시기와 같은 소스에 바인딩할 수 있거나 대상 속성에는 테이블의 데이터 바인딩된 배경색과 같이 변경을 위해 제공된 컨트롤 인터페이스가 없을 수 있습니다.For instance, you may bind to a source such as a stock ticker, or perhaps your target property has no control interface provided for making changes, such as a data-bound background color of a table. 대상 속성의 변경 내용을 모니터링할 필요가 없는 경우 OneWay 바인딩 모드를 사용하면 TwoWay 바인딩 모드의 오버헤드가 방지됩니다.If there is no need to monitor the changes of the target property, using the OneWay binding mode avoids the overhead of the TwoWay binding mode.

  • TwoWay 바인딩으로 인해 소스 속성 또는 대상 속성이 변경되어 다른 항목이 자동으로 업데이트됩니다.TwoWay binding causes changes to either the source property or the target property to automatically update the other. 이 바인딩 유형은 편집 가능한 형식이나 기타 완전한 대화형 UI 시나리오에 적합합니다.This type of binding is appropriate for editable forms or other fully interactive UI scenarios. 대부분의 속성은 기본적으로 OneWay 바인딩으로 설정되지만, 일부 종속성 속성(일반적으로 TextBox.TextCheckBox.IsChecked와 같이 사용자가 편집할 수 있는 컨트롤의 속성)은 기본적으로 TwoWay 바인딩으로 설정됩니다.Most properties default to OneWay binding, but some dependency properties (typically properties of user-editable controls such as the TextBox.Text and CheckBox.IsChecked default to TwoWay binding. 종속성 속성이 기본적으로 단방향 또는 양방향으로 바인딩되는지를 프로그래밍 방식으로 결정하려면 DependencyProperty.GetMetadata를 사용하여 속성 메타데이터를 가져온 후 FrameworkPropertyMetadata.BindsTwoWayByDefault 속성의 부울 값을 확인합니다.A programmatic way to determine whether a dependency property binds one-way or two-way by default is to get the property metadata with DependencyProperty.GetMetadata and then check the Boolean value of the FrameworkPropertyMetadata.BindsTwoWayByDefault property.

  • OneWayToSourceOneWay 바인딩의 반대로, 대상 속성이 변경되면 소스 속성을 업데이트합니다.OneWayToSource is the reverse of OneWay binding; it updates the source property when the target property changes. UI에서 소스 값을 다시 평가하면 되는 경우가 한 가지 예제 시나리오입니다.One example scenario is if you only need to reevaluate the source value from the UI.

  • 그림에는 나타나지 않지만 OneTime 바인딩을 사용하면 소스 속성이 대상 속성을 초기화하지만 이후 변경 내용을 전파하지 않습니다.Not illustrated in the figure is OneTime binding, which causes the source property to initialize the target property but does not propagate subsequent changes. 데이터 컨텍스트가 변경되거나 데이터 컨텍스트의 개체가 변경될 경우 변경 내용이 대상 속성에 반영되지 ‘않습니다’.If the data context changes or the object in the data context changes, the change is not reflected in the target property. 이 바인딩 유형은 현재 상태의 스냅샷이 적절하거나 데이터가 실제로 정적인 경우에 적합합니다.This type of binding is appropriate if either a snapshot of the current state is appropriate or the data is truly static. 또한 이 바인딩 유형은 원본 속성의 일부 값으로 대상 속성을 초기화하려고 하며 데이터 컨텍스트가 사전에 알려지지 않은 경우에도 유용합니다.This type of binding is also useful if you want to initialize your target property with some value from a source property and the data context is not known in advance. 이 모드는 기본적으로 소스 값이 변경되지 않은 경우에 더 나은 성능을 제공하는 OneWay 바인딩의 더 간단한 형식입니다.This mode is essentially a simpler form of OneWay binding that provides better performance in cases where the source value does not change.

소스 변경 내용을 검색하려면(OneWayTwoWay 바인딩에 적용 가능) 소스에서 INotifyPropertyChanged와 같은 적절한 속성 변경 알림 메커니즘을 구현해야 합니다.To detect source changes (applicable to OneWay and TwoWay bindings), the source must implement a suitable property change notification mechanism such as INotifyPropertyChanged. 방법: 속성 변경 알림 구현에서 INotifyPropertyChanged 구현의 예제를 참조하세요.See How to: Implement property change notification for an example of an INotifyPropertyChanged implementation.

Binding.Mode 속성은 바인딩 모드에 관한 자세한 설명과 바인딩 방향을 지정하는 방법의 예제를 제공합니다.The Binding.Mode property provides more information about binding modes and an example of how to specify the direction of a binding.

소스 업데이트를 트리거하는 항목What triggers source updates

TwoWay 또는 OneWayToSource인 바인딩은 대상 속성의 변경 내용을 수신하고 다시 소스에 전파합니다. 이를 소스 업데이트라고 합니다.Bindings that are TwoWay or OneWayToSource listen for changes in the target property and propagate them back to the source, known as updating the source. 예를 들어 TextBox의 텍스트를 편집하여 기본 소스 값을 변경할 수 있습니다.For example, you may edit the text of a TextBox to change the underlying source value.

하지만 텍스트를 편집하는 동안이나 텍스트 편집을 마치고 컨트롤이 포커스를 잃은 후 소스 값이 업데이트될까요?However, is your source value updated while you are editing the text or after you finish editing the text and the control loses focus? Binding.UpdateSourceTrigger 속성은 소스 업데이트를 트리거하는 항목을 결정합니다.The Binding.UpdateSourceTrigger property determines what triggers the update of the source. 다음 그림에서 오른쪽 화살표의 점은 Binding.UpdateSourceTrigger 속성의 역할을 보여 줍니다.The dots of the right arrows in the following figure illustrate the role of the Binding.UpdateSourceTrigger property.

UpdateSourceTrigger 속성의 역할을 보여 주는 다이어그램.

UpdateSourceTrigger 값이 UpdateSourceTrigger.PropertyChanged이면 대상 속성이 변경되는 즉시 TwoWay 또는 OneWayToSource 바인딩의 오른쪽 화살표가 가리키는 값이 업데이트됩니다.If the UpdateSourceTrigger value is UpdateSourceTrigger.PropertyChanged, then the value pointed to by the right arrow of TwoWay or the OneWayToSource bindings is updated as soon as the target property changes. 하지만 UpdateSourceTrigger 값이 LostFocus이면 대상 속성이 포커스를 잃을 경우에만 이 값이 새 값으로 업데이트됩니다.However, if the UpdateSourceTrigger value is LostFocus, then that value only is updated with the new value when the target property loses focus.

Mode 속성과 비슷하게 종속성 속성에 따라 기본 UpdateSourceTrigger 값이 다릅니다.Similar to the Mode property, different dependency properties have different default UpdateSourceTrigger values. 대부분의 종속성 속성에 대한 기본값이 PropertyChanged인 반면 TextBox.Text 속성의 기본값은 LostFocus입니다.The default value for most dependency properties is PropertyChanged, while the TextBox.Text property has a default value of LostFocus. PropertyChanged는 대개 대상 속성이 변경될 때마다 소스 업데이트가 수행됨을 의미합니다.PropertyChanged means the source updates usually happen whenever the target property changes. 즉각적인 변경 내용은 CheckBoxes 및 기타 간단한 컨트롤에 적합합니다.Instant changes are fine for CheckBoxes and other simple controls. 하지만 텍스트 필드의 경우 키 입력이 있을 때마다 업데이트하면 성능이 저하될 수 있고 새 값으로 커밋하기 전에 사용자가 백스페이스 키를 누르고 입력 오류를 수정할 수 있는 기회가 사라집니다.However, for text fields, updating after every keystroke can diminish performance and denies the user the usual opportunity to backspace and fix typing errors before committing to the new value.

종속성 속성의 기본값을 찾는 방법에 관한 자세한 내용은 UpdateSourceTrigger 속성 페이지를 참조하세요.See the UpdateSourceTrigger property page for information about how to find the default value of a dependency property.

다음 표에는 TextBox를 예제로 사용하는 각 UpdateSourceTrigger 값의 예제 시나리오가 나와 있습니다.The following table provides an example scenario for each UpdateSourceTrigger value using the TextBox as an example.

UpdateSourceTrigger 값UpdateSourceTrigger value 소스 값이 업데이트될 때When the source value is updated TextBox의 예제 시나리오Example scenario for TextBox
LostFocus(TextBox.Text의 기본값)LostFocus (default for TextBox.Text) TextBox 컨트롤이 포커스를 잃을 때.When the TextBox control loses focus. 유효성 검사 논리와 연결된 TextBox(아래 데이터 유효성 검사 참조).A TextBox that is associated with validation logic (see Data Validation below).
PropertyChanged TextBox에 입력할 때.As you type into the TextBox. 대화방 창의 TextBox 컨트롤.TextBox controls in a chat room window.
Explicit 앱이 UpdateSource를 호출할 때.When the app calls UpdateSource. 편집 가능한 양식의 TextBox 컨트롤(사용자가 제출 단추를 클릭할 경우에만 소스 값 업데이트).TextBox controls in an editable form (updates the source values only when the user clicks the submit button).

예는 방법: TextBox 텍스트의 소스를 업데이트하는 시점 제어를 참조하세요.For an example, see How to: Control when the TextBox text updates the source.

바인딩 만들기Creating a binding

이전 섹션에서 설명한 일부 개념을 다시 설명하면, Binding 개체를 사용하여 바인딩을 설정하고 각 바인딩에는 일반적으로 네 가지 구성 요소인 바인딩 대상, 대상 속성, 바인딩 소스 및 사용할 소스 값이 포함됩니다.To restate some of the concepts discussed in the previous sections, you establish a binding using the Binding object, and each binding usually has four components: a binding target, a target property, a binding source, and a path to the source value to use. 이 섹션에서는 바인딩을 설정하는 방법을 설명합니다.This section discusses how to set up a binding.

바인딩 소스 개체가 SDKSample 네임스페이스에 정의된 MyData 클래스인 다음 예제를 살펴볼 수 있습니다.Consider the following example, in which the binding source object is a class named MyData that is defined in the SDKSample namespace. 설명을 위해 MyData 에는 값이 “Red”로 설정된 ColorName 문자열 속성이 있습니다.For demonstration purposes, MyData has a string property named ColorName whose value is set to "Red". 따라서 이 예제에서는 빨간색 배경이 있는 단추를 생성합니다.Thus, this example generates a button with a red background.

<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://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>

바인딩 선언 구문에 관한 자세한 설명과 코드에서 바인딩을 설정하는 방법의 예제는 바인딩 선언 개요를 참조하세요.For more information on the binding declaration syntax and examples of how to set up a binding in code, see Binding Declarations Overview.

이 예제를 기본 다이어그램에 적용하면 결과 그림은 다음과 같이 표시됩니다.If we apply this example to our basic diagram, the resulting figure looks like the following. Background 속성이 기본적으로 OneWay 바인딩을 지원하므로 이 그림에서는 OneWay 바인딩을 설명합니다.This figure describes a OneWay binding because the Background property supports OneWay binding by default.

데이터 바인딩 Background 속성을 보여 주는 다이어그램.

Background 속성이 Brush 형식인데 ColorName 속성이 형식 문자열인 경우에도 이 바인딩이 작동하는 이유가 궁금할 수 있습니다.You may wonder why this binding works even though the ColorName property is of type string while the Background property is of type Brush. 이 바인딩은 기본 형식 변환을 사용하며 이 기능은 데이터 변환 섹션에서 설명합니다.This binding uses default type conversion, which is discussed in the Data conversion section.

바인딩 소스 지정Specifying the binding source

이전 예제에서는 DockPanel.DataContext 속성을 설정하여 바인딩 소스를 지정합니다.Notice that in the previous example, the binding source is specified by setting the DockPanel.DataContext property. 그런 다음, Button은 부모 요소인 DockPanel에서 DataContext 값을 상속합니다.The Button then inherits the DataContext value from the DockPanel, which is its parent element. 다시 말하지만, 바인딩 소스 개체는 바인딩의 네 가지 필수 구성 요소 중 하나입니다.To reiterate, the binding source object is one of the four necessary components of a binding. 따라서 바인딩 소스 개체를 지정하지 않으면 바인딩은 아무 작업도 하지 않습니다.Therefore, without the binding source object being specified, the binding would do nothing.

바인딩 소스 개체를 지정하는 여러 가지 방법이 있습니다.There are several ways to specify the binding source object. 여러 속성을 같은 소스에 바인딩할 경우 부모 요소에서 DataContext 속성을 사용하는 방법이 유용합니다.Using the DataContext property on a parent element is useful when you are binding multiple properties to the same source. 하지만 개별 바인딩 선언에서 바인딩 소스를 지정하는 방법이 더 적절한 경우도 있습니다.However, sometimes it may be more appropriate to specify the binding source on individual binding declarations. 이전 예제에서는 DataContext 속성을 사용하지 않고 다음 예제와 같이 단추의 바인딩 선언에서 직접 Binding.Source 속성을 설정하여 바인딩 소스를 지정할 수 있습니다.For the previous example, instead of using the DataContext property, you can specify the binding source by setting the Binding.Source property directly on the binding declaration of the button, as in the following example.

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

요소에서 직접 DataContext 속성을 설정하지 않고, 상위 항목(예: 첫 번째 예제의 단추)에서 DataContext 값을 상속하고 바인딩에서 Binding.Source 속성(예: 마지막 예제의 단추)을 설정하여 바인딩 소스를 명시적으로 지정하면 Binding.ElementName 속성이나 Binding.RelativeSource 속성을 사용하여 바인딩 소스를 지정할 수도 있습니다.Other than setting the DataContext property on an element directly, inheriting the DataContext value from an ancestor (such as the button in the first example), and explicitly specifying the binding source by setting the Binding.Source property on the binding (such as the button the last example), you can also use the Binding.ElementName property or the Binding.RelativeSource property to specify the binding source. 슬라이더를 사용하여 단추 너비를 조정하는 경우와 같이 앱에서 다른 요소에 바인딩할 경우에는 ElementName 속성이 유용합니다.The ElementName property is useful when you are binding to other elements in your app, such as when you are using a slider to adjust the width of a button. 바인딩이 ControlTemplate 또는 Style에서 지정되는 경우 RelativeSource 속성이 유용합니다.The RelativeSource property is useful when the binding is specified in a ControlTemplate or a Style. 자세한 내용은 방법: 바인딩 소스 지정을 참조하세요.For more information, see How to: Specify the binding source.

값 경로 지정Specifying the path to the value

바인딩 소스가 개체이면 Binding.Path 속성을 사용하여 바인딩에 사용할 값을 지정합니다.If your binding source is an object, you use the Binding.Path property to specify the value to use for your binding. XML 데이터에 바인딩할 경우에는 Binding.XPath 속성을 사용하여 값을 지정합니다.If you are binding to XML data, you use the Binding.XPath property to specify the value. 경우에 따라 데이터가 XML이더라도 Path 속성을 사용하는 것이 좋을 수 있습니다.In some cases, it may be applicable to use the Path property even when your data is XML. 예를 들어 XPath 쿼리의 결과로 반환된 XmlNode의 Name 속성에 액세스하려면 XPath 속성 외에 Path 속성을 사용해야 합니다.For example, if you want to access the Name property of a returned XmlNode (as a result of an XPath query), you should use the Path property in addition to the XPath property.

자세한 내용은 PathXPath 속성을 참조하세요.For more information, see the Path and XPath properties.

사용할 값의 Path가 네 가지 필수 구성 요소 중 하나임을 강조했지만, 전체 개체에 바인딩하려는 시나리오에서는 사용할 값이 바인딩 소스 개체와 같습니다.Although we have emphasized that the Path to the value to use is one of the four necessary components of a binding, in the scenarios that you want to bind to an entire object, the value to use would be the same as the binding source object. 이 경우에는 Path를 지정하지 않는 것이 좋을 수 없습니다.In those cases, it is applicable to not specify a Path. 다음 예제를 살펴보십시오.Consider the following example.

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

위의 예제에서는 빈 바인딩 구문인 {Binding}을 사용합니다.The above example uses the empty binding syntax: {Binding}. 이 경우 ListBox는 부모 DockPanel 요소(이 예제에는 표시되지 않음)에서 DataContext를 상속합니다.In this case, the ListBox inherits the DataContext from a parent DockPanel element (not shown in this example). 경로를 지정하지 않으면 기본적으로 전체 개체에 바인딩됩니다.When the path is not specified, the default is to bind to the entire object. 즉, 이 예제에서는 ItemsSource 속성을 전체 개체에 바인딩하므로 경로가 비어 있습니다.In other words, in this example, the path has been left out because we are binding the ItemsSource property to the entire object. 자세한 내용은 컬렉션에 바인딩 섹션을 참조하세요.(See the Binding to collections section for an in-depth discussion.)

컬렉션에 바인딩 외에 개체의 단일 속성만이 아닌 전체 개체에 바인딩하려는 경우에도 이 시나리오가 유용합니다.Other than binding to a collection, this scenario is also useful when you want to bind to an entire object instead of just a single property of an object. 예를 들면 소스 개체가 String 형식이고 문자열 자체에 바인딩하려는 경우일 수 있습니다.For example, if your source object is of type String, you may simply want to bind to the string itself. 또 다른 일반적인 시나리오는 여러 속성이 있는 개체에 요소를 바인딩하려는 경우입니다.Another common scenario is when you want to bind an element to an object with several properties.

바인딩된 대상 속성에서 데이터가 의미를 가지려면 사용자 지정 논리를 적용해야 할 수 있습니다.You may need to apply custom logic so that the data is meaningful to your bound target property. 기본 형식 변환이 없는 경우 사용자 지정 논리는 사용자 지정 변환기 형식일 수 있습니다.The custom logic may be in the form of a custom converter if default type conversion does not exist. 변환기에 관한 자세한 내용은 데이터 변환을 참조하세요.See Data conversion for information about converters.

Binding 및 BindingExpressionBinding and BindingExpression

데이터 바인딩의 다른 기능과 사용법을 살펴보기 전에 BindingExpression 클래스를 알아보는 것이 도움이 됩니다.Before getting into other features and usages of data binding, it is useful to introduce the BindingExpression class. 이전 섹션에서 살펴본 대로 Binding 클래스는 바인딩 선언의 상위 수준 클래스입니다. 이 클래스는 바인딩의 특징을 지정할 수 있는 다양한 속성을 제공합니다.As you have seen in previous sections, the Binding class is the high-level class for the declaration of a binding; it provides many properties that allow you to specify the characteristics of a binding. 관련 클래스인 BindingExpression은 소스와 대상 간에 연결을 유지 관리하는 기본 개체입니다.A related class, BindingExpression, is the underlying object that maintains the connection between the source and the target. 바인딩에는 여러 바인딩 식에서 공유될 수 있는 모든 정보가 포함됩니다.A binding contains all the information that can be shared across several binding expressions. BindingExpression은 공유될 수 없는 인스턴스 식이고 Binding의 모든 인스턴스 정보를 포함합니다.A BindingExpression is an instance expression that cannot be shared and contains all the instance information of the Binding.

다음 예제를 참조하세요. 여기서 myDataObjectMyData 클래스의 인스턴스이고, myBinding은 소스 Binding 개체이며, MyDataColorName 문자열 속성을 포함하는 정의된 클래스입니다.Consider the following example, where myDataObject is an instance of the MyData class, myBinding is the source Binding object, and MyData is a defined class that contains a string property named ColorName. 이 예제에서는 TextBlock의 인스턴스인 myText의 텍스트 콘텐츠를 ColorName에 바인딩합니다.This example binds the text content of myText, an instance of TextBlock, to ColorName.

// Make a new source
var myDataObject = new MyData();
var myBinding = new Binding("ColorName")
{
    Source = myDataObject
};

// Bind the data source to the TextBox control's Text dependency property
myText.SetBinding(TextBlock.TextProperty, myBinding);
' Make a New source
Dim myDataObject As New MyData
Dim myBinding As New Binding("ColorName")
myBinding.Source = myDataObject

' Bind the data source to the TextBox control's Text dependency property
myText.SetBinding(TextBlock.TextProperty, myBinding)

같은 myBinding 개체를 사용하여 다른 바인딩을 만들 수 있습니다.You can use the same myBinding object to create other bindings. 예를 들어 myBinding 개체를 사용하여 확인란의 텍스트 콘텐츠를 ColorName 에 바인딩할 수 있습니다.For example, you can use the myBinding object to bind the text content of a check box to ColorName. 이 시나리오에는 myBinding 개체를 공유하는 두 개의 BindingExpression 인스턴스가 있습니다.In that scenario, there will be two instances of BindingExpression sharing the myBinding object.

BindingExpression 개체는 데이터에 바인딩된 개체에서 GetBindingExpression을 호출하여 반환됩니다.A BindingExpression object is returned by calling GetBindingExpression on a data-bound object. 다음 문서에서는 BindingExpression 클래스를 사용하는 몇 가지 방법을 설명합니다.The following articles demonstrate some of the usages of the BindingExpression class:

데이터 변환Data conversion

바인딩 만들기 섹션에서는 Background 속성이 값이 "Red"인 문자열 속성에 바인딩되므로 단추가 빨간색입니다.In the Creating a binding section, the button is red because its Background property is bound to a string property with the value "Red". 이 문자열 값은 문자열 값을 Brush로 변환하는 Brush 형식에 대한 형식 변환기가 있기 때문에 가능합니다.This string value works because a type converter is present on the Brush type to convert the string value to a Brush.

이 정보를 그림에 추가하면 바인딩 만들기 섹션은 다음과 같이 표시됩니다.Adding this information to the figure in the Creating a Binding section looks like this.

데이터 바인딩 Default 속성을 보여 주는 다이어그램.

하지만 바인딩 소스 개체에 문자열 형식의 속성이 아닌 Color 형식의 Color 속성이 있으면 어떻게 될까요?However, what if instead of having a property of type string your binding source object has a Color property of type Color? 이 경우 바인딩을 적용하려면 먼저 Color 속성 값을 Background 속성이 사용하는 어떤 것으로 변환해야 합니다.In that case, in order for the binding to work you would need to first turn the Color property value into something that the Background property accepts. 다음 예제와 같이 IValueConverter 인터페이스를 구현하여 사용자 지정 변환기를 만들어야 합니다.You would need to create a custom converter by implementing the IValueConverter interface, as in the following example.

[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;
    }
}
<ValueConversion(GetType(Color), GetType(SolidColorBrush))>
Public Class ColorBrushConverter
    Implements IValueConverter
    Public Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.Convert
        Dim color As Color = CType(value, Color)
        Return New SolidColorBrush(color)
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
        Return Nothing
    End Function
End Class

자세한 내용은 IValueConverter를 참조하세요.See IValueConverter for more information.

이제 기본 변환 대신 사용자 지정 변환기가 사용되고 다이어그램이 다음과 같이 표시됩니다.Now the custom converter is used instead of default conversion, and our diagram looks like this.

데이터 바인딩 사용자 지정 변환기를 보여 주는 다이어그램.

다시 말하지만, 바인딩되는 형식에 있는 형식 변환기 때문에 기본 변환을 사용할 수 있습니다.To reiterate, default conversions may be available because of type converters that are present in the type being bound to. 이 동작은 대상에서 사용할 수 있는 형식 변환기에 따라 결정됩니다.This behavior will depend on which type converters are available in the target. 확실하지 않으면 사용자 지정 변환기를 만듭니다.If in doubt, create your own converter.

데이터 변환기를 구현하는 것이 좋은 몇 가지 일반적인 시나리오는 다음과 같습니다.The following are some typical scenarios where it makes sense to implement a data converter:

  • 데이터를 문화권에 따라 다르게 표시해야 하는 경우.Your data should be displayed differently, depending on culture. 예를 들어 특정 문화권에서 사용되는 규칙에 따라 통화 변환기 또는 달력 날짜/시간 변환기를 구현해야 할 수 있습니다.For instance, you might want to implement a currency converter or a calendar date/time converter based on the conventions used in a particular culture.

  • 사용되는 데이터가 반드시 속성의 텍스트 값을 변경하는 데 사용될 필요는 없지만, 이미지의 소스 또는 표시 텍스트의 색이나 스타일과 같은 몇 가지 다른 값을 변경하는 데 사용되는 경우.The data being used is not necessarily intended to change the text value of a property, but is instead intended to change some other value, such as the source for an image, or the color or style of the display text. 텍스트 필드를 표 셀의 Background 속성에 바인딩하는 것과 같이 적절해 보이지 않는 속성의 바인딩을 변환하는 방식으로 이 인스턴스에서 변환기를 사용할 수 있습니다.Converters can be used in this instance by converting the binding of a property that might not seem to be appropriate, such as binding a text field to the Background property of a table cell.

  • 두 개 이상의 컨트롤 또는 컨트롤의 여러 속성이 같은 데이터에 바인딩됩니다.More than one control or multiple properties of controls are bound to the same data. 이 경우 기본 바인딩은 텍스트만 표시할 수 있는 반면, 기타 바인딩은 특정 표시 문제를 처리하지만 소스 정보와 같은 바인딩을 사용합니다.In this case, the primary binding might just display the text, whereas other bindings handle specific display issues but still use the same binding as source information.

  • 대상 속성에는 MultiBinding이라는 바인딩 컬렉션이 있습니다.A target property has a collection of bindings, which is termed MultiBinding. MultiBinding의 경우 사용자 지정 IMultiValueConverter를 사용하여 바인딩의 값에서 최종 값을 생성합니다.For MultiBinding, you use a custom IMultiValueConverter to produce a final value from the values of the bindings. 예를 들어 빨간색, 파란색 및 녹색 값을 기준으로 색을 계산할 수 있고 이러한 값은 같거나 다른 바인딩 소스 개체의 값일 수 있습니다.For example, color may be computed from red, blue, and green values, which can be values from the same or different binding source objects. 예제와 자세한 내용은 MultiBinding을 참조하세요.See MultiBinding for examples and information.

컬렉션에 바인딩Binding to collections

바인딩 소스는 속성에 데이터가 포함된 단일 개체로 처리되거나 종종 함께 그룹화되는 다형 개체의 데이터 수집(예: 데이터베이스에 대한 쿼리의 결과)으로 처리될 수 있습니다.A binding source object can be treated either as a single object whose properties contain data or as a data collection of polymorphic objects that are often grouped together (such as the result of a query to a database). 지금까지 단일 개체에 대한 바인딩만 설명했습니다.So far we've only discussed binding to single objects. 그러나 일반적인 시나리오는 데이터 수집에 대한 바인딩입니다.However, binding to a data collection is a common scenario. 예를 들어 일반적인 시나리오는 ListBox, ListView 또는 TreeView와 같은 ItemsControl을 사용하여 데이터 바인딩이란? 섹션에 나와 있는 앱과 같이 데이터 수집을 표시하는 것입니다.For example, a common scenario is to use an ItemsControl such as a ListBox, ListView, or TreeView to display a data collection, such as in the app shown in the What is data binding section.

다행히도 기본 다이어그램이 적용됩니다.Fortunately, our basic diagram still applies. ItemsControl을 컬렉션에 바인딩할 경우 다이어그램은 다음과 같이 표시됩니다.If you are binding an ItemsControl to a collection, the diagram looks like this.

데이터 바인딩 ItemsControl 개체를 보여 주는 다이어그램.

이 다이어그램과 같이 ItemsControl을 컬렉션 개체에 바인딩하는 데 사용할 속성은 ItemsControl.ItemsSource 속성입니다.As shown in this diagram, to bind an ItemsControl to a collection object, ItemsControl.ItemsSource property is the property to use. ItemsSourceItemsControl의 콘텐츠로 간주할 수 있습니다.You can think of ItemsSource as the content of the ItemsControl. ItemsSource 속성은 기본적으로 OneWay 바인딩을 지원하므로 바인딩은 OneWay입니다.The binding is OneWay because the ItemsSource property supports OneWay binding by default.

컬렉션을 구현하는 방법How to implement collections

IEnumerable 인터페이스를 구현하는 컬렉션을 열거할 수 있습니다.You can enumerate over any collection that implements the IEnumerable interface. 그러나 컬렉션에서 삽입 또는 삭제가 발생할 때마다 UI가 자동으로 업데이트되도록 동적 바인딩을 설정하려면 컬렉션이 INotifyCollectionChanged 인터페이스를 구현해야 합니다.However, to set up dynamic bindings so that insertions or deletions in the collection update the UI automatically, the collection must implement the INotifyCollectionChanged interface. 이 인터페이스는 기본 컬렉션이 변경될 때마다 발생해야 하는 이벤트를 노출합니다.This interface exposes an event that should be raised whenever the underlying collection changes.

WPF는 ObservableCollection<T> 클래스를 제공하고 이 클래스는 INotifyCollectionChanged 인터페이스를 노출하는 데이터 수집의 기본 구현입니다.WPF provides the ObservableCollection<T> class, which is a built-in implementation of a data collection that exposes the INotifyCollectionChanged interface. 소스 개체에서 대상으로 데이터 값을 전송하는 기능을 완전히 지원하려면 바인딩 가능 속성을 지원하는 컬렉션의 각 개체도 INotifyPropertyChanged 인터페이스를 구현해야 합니다.To fully support transferring data values from source objects to targets, each object in your collection that supports bindable properties must also implement the INotifyPropertyChanged interface. 자세한 내용은 바인딩 소스 개요를 참조하세요.For more information, see Binding sources overview.

고유한 컬렉션을 구현하기 전에 ObservableCollection<T>을 사용하거나 List<T>, Collection<T>BindingList<T>와 같은 기존 컬렉션 클래스 중 하나를 사용하는 것이 좋습니다.Before implementing your own collection, consider using ObservableCollection<T> or one of the existing collection classes, such as List<T>, Collection<T>, and BindingList<T>, among many others. 고급 시나리오가 있고 사용자 지정 컬렉션을 구현하려면 인덱스를 통해 개별적으로 액세스할 수 있는 제네릭이 아닌 컬렉션을 제공하므로 최고의 성능을 제공하는 IList를 사용하는 것이 좋습니다.If you have an advanced scenario and want to implement your own collection, consider using IList, which provides a non-generic collection of objects that can be individually accessed by the index, and thus provides the best performance.

컬렉션 뷰Collection views

ItemsControl이 데이터 수집에 바인딩된 후 데이터를 정렬, 필터링 또는 그룹화해야 할 수 있습니다.Once your ItemsControl is bound to a data collection, you may want to sort, filter, or group the data. 이 작업을 수행하는 데는 ICollectionView 인터페이스를 구현하는 클래스인 컬렉션 뷰를 사용합니다.To do that, you use collection views, which are classes that implement the ICollectionView interface.

컬렉션 뷰란?What Are collection views?

컬렉션 뷰는 기본 소스 컬렉션 자체를 변경할 필요 없이 정렬, 필터 및 그룹화 쿼리에 따라 소스 컬렉션을 탐색하고 표시할 수 있는 바인딩 소스 컬렉션의 최상위에 있는 레이어입니다.A collection view is a layer on top of a binding source collection that allows you to navigate and display the source collection based on sort, filter, and group queries, without having to change the underlying source collection itself. 컬렉션 뷰에서는 컬렉션의 현재 항목에 대한 포인터도 유지 관리합니다.A collection view also maintains a pointer to the current item in the collection. 소스 컬렉션이 INotifyCollectionChanged 인터페이스를 구현하면 CollectionChanged 이벤트를 통해 변경된 내용이 뷰에 전파됩니다.If the source collection implements the INotifyCollectionChanged interface, the changes raised by the CollectionChanged event are propagated to the views.

뷰는 기본 소스 컬렉션을 변경하지 않으므로 각 소스 컬렉션에는 연결된 여러 뷰가 있을 수 있습니다.Because views do not change the underlying source collections, each source collection can have multiple views associated with it. 예를 들어 Task 개체의 컬렉션이 있을 수 있습니다.For example, you may have a collection of Task objects. 뷰를 사용하여 같은 데이터를 다양한 방식으로 표시할 수 있습니다.With the use of views, you can display that same data in different ways. 예를 들어 페이지 왼쪽에는 우선 순위별로 정렬된 작업을 표시하고 오른쪽에는 영역별로 그룹화된 작업을 표시해야 할 수 있습니다.For example, on the left side of your page you may want to show tasks sorted by priority, and on the right side, grouped by area.

뷰를 만드는 방법How to create a view

뷰를 만들고 사용하는 한 가지 방법은 뷰 개체를 인스턴스화하고 이를 바인딩 소스로 사용하는 것입니다.One way to create and use a view is to instantiate the view object directly and then use it as the binding source. 예를 들어 데이터 바인딩이란? 섹션에 나와 있는 Data binding demo(데이터 바인딩 데모) 앱을 살펴보겠습니다.For example, consider the Data binding demo app shown in the What is data binding section. 이 앱은 ListBox가 데이터 수집에 직접 바인딩되지 않고 데이터 수집을 통해 뷰에 바인딩되도록 구현됩니다.The app is implemented such that the ListBox binds to a view over the data collection instead of the data collection directly. 다음 예제는 Data Binding Demo(데이터 바인딩 데모) 앱에서 추출됩니다.The following example is extracted from the Data binding demo app. CollectionViewSource 클래스는 CollectionView에서 상속되는 클래스의 XAML 프록시입니다.The CollectionViewSource class is the XAML proxy of a class that inherits from CollectionView. 이 특정 예제에서 뷰의 Source는 현재 앱 개체의 AuctionItems 컬렉션(ObservableCollection<T> 형식)에 바인딩됩니다.In this particular example, the Source of the view is bound to the AuctionItems collection (of type ObservableCollection<T>) of the current app object.

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

리소스 listingDataView 는 앱에 있는 ListBox와 같은 요소의 바인딩 소스로 사용됩니다.The resource listingDataView then serves as the binding source for elements in the app, such as the ListBox.

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

같은 컬렉션에 대한 또 다른 뷰를 만들려면 또 다른 CollectionViewSource 인스턴스를 만들고 다른 x:Key 이름을 지정할 수 있습니다.To create another view for the same collection, you can create another CollectionViewSource instance and give it a different x:Key name.

다음 표에서는 기본 컬렉션 뷰로 만들어지거나 소스 컬렉션 형식에 따라 CollectionViewSource를 통해 만들어지는 뷰 데이터 형식을 보여 줍니다.The following table shows what view data types are created as the default collection view or by CollectionViewSource based on the source collection type.

소스 컬렉션 형식Source collection type 컬렉션 뷰 형식Collection view type 참고Notes
IEnumerable CollectionView를 기반으로 하는 내부 형식An internal type based on CollectionView 항목을 그룹화할 수 없습니다.Cannot group items.
IList ListCollectionView 가장 빠릅니다.Fastest.
IBindingList BindingListCollectionView

기본 뷰 사용Using a default view

컬렉션 뷰를 만들고 사용하는 한 가지 방법은 컬렉션 뷰를 바인딩 소스로 지정하는 것입니다.Specifying a collection view as a binding source is one way to create and use a collection view. WPF에서도 바인딩 소스로 사용되는 모든 컬렉션에 대한 기본 컬렉션 뷰를 만듭니다.WPF also creates a default collection view for every collection used as a binding source. 컬렉션에 직접 바인딩할 경우 WPF는 기본 뷰에 바인딩됩니다.If you bind directly to a collection, WPF binds to its default view. 같은 컬렉션에 대한 모든 바인딩이 이 기본 뷰를 공유하므로 하나의 바인딩된 컨트롤이나 코드(예: 뒷부분에 설명되는 현재 항목 포인터에 대한 정렬 또는 변경)를 통해 기본 뷰에 적용된 변경 내용은 같은 컬렉션에 대한 모든 다른 바인딩에 반영됩니다.This default view is shared by all bindings to the same collection, so a change made to a default view by one bound control or code (such as sorting or a change to the current item pointer, discussed later) is reflected in all other bindings to the same collection.

기본 뷰를 가져오려면 GetDefaultView 메서드를 사용합니다.To get the default view, you use the GetDefaultView method. 예제를 보려면 데이터 수집의 기본 뷰 가져오기를 참조하세요.For an example, see Get the default view of a data collection.

ADO.NET DataTable이 있는 컬렉션 뷰Collection views with ADO.NET DataTables

성능을 개선하기 위해 ADO.NET DataTable 또는 DataView 개체의 컬렉션 뷰는 정렬 및 필터링을 DataView에 위임하며, 이로 인해 정렬 및 필터링이 데이터 소스의 모든 컬렉션 뷰에서 공유됩니다.To improve performance, collection views for ADO.NET DataTable or DataView objects delegate sorting and filtering to the DataView, which causes sorting and filtering to be shared across all collection views of the data source. 각 컬렉션 뷰를 개별적으로 정렬 및 필터링하려면 자체 DataView 개체를 사용하여 각 컬렉션 뷰를 초기화합니다.To enable each collection view to sort and filter independently, initialize each collection view with its own DataView object.

정렬Sorting

앞에서 설명한 대로 뷰에서는 컬렉션에 정렬 순서를 적용할 수 있습니다.As mentioned before, views can apply a sort order to a collection. 기본 컬렉션에 있는 데이터에는 관련 상속 순서가 있거나 없을 수도 있습니다.As it exists in the underlying collection, your data may or may not have a relevant, inherent order. 컬렉션에 대한 뷰를 통해 제공한 비교 기준에 따라 순서를 적용하거나 기본 순서를 변경할 수 있습니다.The view over the collection allows you to impose an order, or change the default order, based on comparison criteria that you supply. 이는 데이터의 클라이언트 기반 뷰이므로 일반적으로 열과 일치하는 값에 따라 표 형식 데이터의 열을 정렬해야 할 수 있습니다.Because it is a client-based view of the data, a common scenario is that the user might want to sort columns of tabular data per the value that the column corresponds to. 뷰를 사용하면 기본 컬렉션을 변경하거나 컬렉션 콘텐츠를 다시 쿼리할 필요 없이 이 사용자 기반 정렬을 적용할 수 있습니다.Using views, this user-driven sort can be applied, again without making any changes to the underlying collection or even having to requery for the collection content. 예제를 보려면 머리글을 클릭할 때 GridView 열 정렬을 참조하세요.For an example, see Sort a GridView column when a header is clicked.

다음 예제에서는 데이터 바인딩이란? 섹션에 있는 앱 UI의 "Sort by category and date" CheckBox에 관한 정렬 논리를 보여 줍니다.The following example shows the sorting logic of the "Sort by category and date" CheckBox of the app UI in the What is data binding section.

private void AddSortCheckBox_Checked(object sender, RoutedEventArgs e)
{
    // Sort the items first by Category and then by StartDate
    listingDataView.SortDescriptions.Add(new SortDescription("Category", ListSortDirection.Ascending));
    listingDataView.SortDescriptions.Add(new SortDescription("StartDate", ListSortDirection.Ascending));
}
Private Sub AddSortCheckBox_Checked(sender As Object, e As RoutedEventArgs)
    ' Sort the items first by Category And then by StartDate
    listingDataView.SortDescriptions.Add(New SortDescription("Category", ListSortDirection.Ascending))
    listingDataView.SortDescriptions.Add(New SortDescription("StartDate", ListSortDirection.Ascending))
End Sub

필터링Filtering

뷰에서 컬렉션에 필터를 적용할 수 있으므로 뷰에는 전체 컬렉션의 특정 하위 집합만 표시됩니다.Views can also apply a filter to a collection, so that the view shows only a certain subset of the full collection. 데이터에서 조건에 따라 필터링할 수 있습니다.You might filter on a condition in the data. 예를 들어 데이터 바인딩이란? 섹션의 앱이 수행하는 것처럼 "Show only bargains" CheckBox에는 가격이 $25 이상인 항목을 필터링하는 논리가 포함됩니다.For instance, as is done by the app in the What is data binding section, the "Show only bargains" CheckBox contains logic to filter out items that cost $25 or more. 다음 코드는 Filter를 선택할 때 ShowOnlyBargainsFilterCheckBox 이벤트 처리기로 설정하기 위해 실행됩니다.The following code is executed to set ShowOnlyBargainsFilter as the Filter event handler when that CheckBox is selected.

private void AddFilteringCheckBox_Checked(object sender, RoutedEventArgs e)
{
    if (((CheckBox)sender).IsChecked == true)
        listingDataView.Filter += ListingDataView_Filter;
    else
        listingDataView.Filter -= ListingDataView_Filter;
}
Private Sub AddFilteringCheckBox_Checked(sender As Object, e As RoutedEventArgs)
    Dim checkBox = DirectCast(sender, CheckBox)

    If checkBox.IsChecked = True Then
        AddHandler listingDataView.Filter, AddressOf ListingDataView_Filter
    Else
        RemoveHandler listingDataView.Filter, AddressOf ListingDataView_Filter
    End If
End Sub

ShowOnlyBargainsFilter 이벤트 처리기에는 다음과 같은 구현이 있습니다.The ShowOnlyBargainsFilter event handler has the following implementation.

private void ListingDataView_Filter(object sender, FilterEventArgs e)
{
    // Start with everything excluded
    e.Accepted = false;

    // Only inlcude items with a price less than 25
    if (e.Item is AuctionItem product && product.CurrentPrice < 25)
        e.Accepted = true;
}
Private Sub ListingDataView_Filter(sender As Object, e As FilterEventArgs)

    ' Start with everything excluded
    e.Accepted = False

    Dim product As AuctionItem = TryCast(e.Item, AuctionItem)

    If product IsNot Nothing Then

        ' Only include products with prices lower than 25
        If product.CurrentPrice < 25 Then e.Accepted = True

    End If

End Sub

CollectionViewSource 대신 CollectionView 클래스 중 하나를 사용하는 경우 Filter 속성을 사용하여 콜백을 지정합니다.If you are using one of the CollectionView classes directly instead of CollectionViewSource, you would use the Filter property to specify a callback. 예제를 보려면 뷰에서 데이터 필터링을 참조하세요.For an example, see Filter Data in a View.

그룹화Grouping

IEnumerable 컬렉션을 보는 내부 클래스를 제외하고 모든 컬렉션 뷰는 사용자가 컬렉션 뷰의 컬렉션을 논리 그룹으로 분할할 수 있는 ‘그룹화’를 지원합니다.Except for the internal class that views an IEnumerable collection, all collection views support grouping, which allows the user to partition the collection in the collection view into logical groups. 그룹은 사용자가 그룹 목록을 제공하는 경우 명시적 그룹이고 데이터에 따라 그룹이 동적으로 생성되는 경우 암시적 그룹입니다.The groups can be explicit, where the user supplies a list of groups, or implicit, where the groups are generated dynamically depending on the data.

다음 예제에서는 "Group by category" CheckBox의 논리를 보여 줍니다.The following example shows the logic of the "Group by category" CheckBox.

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

다른 그룹화 예제를 보려면 GridView를 구현하는 ListView의 항목 그룹화를 참조하세요.For another grouping example, see Group Items in a ListView That Implements a GridView.

현재 항목 포인터Current item pointers

뷰는 현재 항목의 개념도 지원합니다.Views also support the notion of a current item. 컬렉션 뷰에서 개체를 탐색할 수 있습니다.You can navigate through the objects in a collection view. 탐색할 때 컬렉션의 특정 위치에 있는 개체를 검색할 수 있는 항목 포인터를 이동합니다.As you navigate, you are moving an item pointer that allows you to retrieve the object that exists at that particular location in the collection. 예제를 보려면 데이터 CollectionView의 개체 탐색을 참조하세요.For an example, see Navigate through the objects in a data CollectionView.

WPF는 뷰(지정한 뷰 또는 컬렉션의 기본 뷰)를 통해 컬렉션에 바인딩되므로 컬렉션에 대한 모든 바인딩에는 현재 항목 포인터가 포함됩니다.Because WPF binds to a collection only by using a view (either a view you specify, or the collection's default view), all bindings to collections have a current item pointer. 뷰에 바인딩할 때 Path 값의 슬래시("/") 문자는 뷰의 현재 항목을 지정합니다.When binding to a view, the slash ("/") character in a Path value designates the current item of the view. 다음 예제에서 데이터 컨텍스트는 컬렉션 뷰입니다.In the following example, the data context is a collection view. 첫 줄은 컬렉션에 바인딩됩니다.The first line binds to the collection. 두 번째 줄은 컬렉션의 현재 항목에 바인딩됩니다.The second line binds to the current item in the collection. 세 번째 줄은 컬렉션에 있는 현재 항목의 Description 속성에 바인딩됩니다.The third line binds to the Description property of the current item in the collection.

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

컬렉션 계층 구조를 트래버스하도록 슬래시와 속성 구문을 쌓을 수도 있습니다.The slash and property syntax can also be stacked to traverse a hierarchy of collections. 다음 예제에서는 소스 컬렉션의 현재 항목 속성인 Offices라는 컬렉션의 현재 항목에 바인딩합니다.The following example binds to the current item of a collection named Offices, which is a property of the current item of the source collection.

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

컬렉션에 적용되는 정렬이나 필터링이 현재 항목 포인터에 영향을 미칠 수 있습니다.The current item pointer can be affected by any sorting or filtering that is applied to the collection. 정렬은 현재 항목 포인터를 선택된 마지막 항목에 유지하지만 이제 컬렉션 뷰는 포인터를 중심으로 재구성됩니다.Sorting preserves the current item pointer on the last item selected, but the collection view is now restructured around it. 이전에는 선택된 항목이 목록의 시작 부분에 있었을 수 있지만 이제 선택된 항목이 가운데 부분에 있을 수 있습니다. 필터링은 필터링한 후 선택 항목이 뷰에 남아 있으면 선택된 항목을 유지합니다.(Perhaps the selected item was at the beginning of the list before, but now the selected item might be somewhere in the middle.) Filtering preserves the selected item if that selection remains in view after the filtering. 남아 있지 않으면 현재 항목 포인터는 필터링된 컬렉션 뷰의 첫 번째 항목으로 설정됩니다.Otherwise, the current item pointer is set to the first item of the filtered collection view.

마스터-세부 바인딩 시나리오Master-detail binding scenario

현재 항목의 개념은 컬렉션에서 항목을 탐색하는 경우뿐 아니라 마스터-세부 바인딩 시나리오에도 유용합니다.The notion of a current item is useful not only for navigation of items in a collection, but also for the master-detail binding scenario. 다시 데이터 바인딩이란? 섹션의 앱 UI를 살펴보겠습니다.Consider the app UI in the What is data binding section again. 해당 앱에서 ListBox 내의 선택 항목에 따라 ContentControl에 표시되는 콘텐츠가 결정됩니다.In that app, the selection within the ListBox determines the content shown in the ContentControl. 다르게 설명하자면, ListBox 항목이 선택될 때 ContentControl은 선택된 항목의 세부 정보를 표시합니다.To put it in another way, when a ListBox item is selected, the ContentControl shows the details of the selected item.

간단히 두 개 이상의 컨트롤을 같은 뷰에 바인딩하여 마스터-세부 시나리오를 구현할 수 있습니다.You can implement the master-detail scenario simply by having two or more controls bound to the same view. Data Binding Demo(데이터 바인딩 데모)의 다음 예제에서는 데이터 바인딩이란? 섹션의 앱 UI에 표시되는 ListBoxContentControl의 태그를 보여 줍니다.The following example from the Data binding demo shows the markup of the ListBox and the ContentControl you see on the app UI in the What is data binding section.

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

컨트롤이 둘 다 같은 소스인 listingDataView 정적 리소스에 바인딩되어 있습니다(뷰를 만드는 방법 섹션에서 이 리소스의 정의 참조).Notice that both of the controls are bound to the same source, the listingDataView static resource (see the definition of this resource in the How to create a view section). 이 바인딩은 singleton 개체(이 경우 ContentControl)가 컬렉션에 바인딩될 경우 자동으로 뷰의 CurrentItem에 바인딩되기 때문에 가능합니다.This binding works because when a singleton object (the ContentControl in this case) is bound to a collection view, it automatically binds to the CurrentItem of the view. CollectionViewSource 개체는 통화 및 선택 항목을 자동으로 동기화합니다.The CollectionViewSource objects automatically synchronize currency and selection. 이 예제에서 목록 컨트롤이 CollectionViewSource 개체에 바인딩되지 않은 경우에는 IsSynchronizedWithCurrentItem 속성을 true로 설정해야 이 기능이 작동합니다.If your list control is not bound to a CollectionViewSource object as in this example, then you would need to set its IsSynchronizedWithCurrentItem property to true for this to work.

다른 예제를 보려면 선택에 따라 컬렉션 및 표시 정보에 바인딩계층적 데이터에 마스터-세부 패턴 사용을 참조하세요.For other examples, see Bind to a collection and display information based on selection and Use the master-detail pattern with hierarchical data.

위 예제에서는 템플릿을 사용합니다.You may have noticed that the above example uses a template. 실제로 템플릿(ContentControl에서 명시적으로 사용되는 템플릿 및 ListBox에서 암시적으로 사용되는 템플릿)을 사용하지 않으면 데이터가 원하는 방식으로 표시되지 않습니다.In fact, the data would not be displayed the way we wish without the use of templates (the one explicitly used by the ContentControl and the one implicitly used by the ListBox). 이제 다음 섹션에서 데이터 템플릿을 살펴보겠습니다.We now turn to data templating in the next section.

데이터 템플릿Data templating

데이터 템플릿을 사용하지 않으면 데이터 바인딩이란? 섹션의 앱 UI가 다음과 같이 표시됩니다.Without the use of data templates, our app UI in the What is data binding section would look like the following.

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

이전 섹션의 예제와 같이 ListBox 컨트롤과 ContentControl이 둘 다 AuctionItem 의 전체 컬렉션 개체(또는 더 구체적으로는 컬렉션 개체에 대한 뷰)에 바인딩됩니다.As shown in the example in the previous section, both the ListBox control and the ContentControl are bound to the entire collection object (or more specifically, the view over the collection object) of AuctionItem s. 데이터 수집을 표시하는 방법에 대한 구체적인 명령이 없으면 ListBox는 기본 컬렉션에 있는 각 개체의 문자열 표현을 표시하고 ContentControl은 바인딩된 개체의 문자열 표현을 표시합니다.Without specific instructions of how to display the data collection, the ListBox displays the string representation of each object in the underlying collection, and the ContentControl displays the string representation of the object it is bound to.

이 문제를 해결하기 위해 앱은 DataTemplates를 정의합니다.To solve that problem, the app defines DataTemplates. 이전 섹션의 예제와 같이 ContentControldetailsProductListingTemplate 데이터 템플릿을 명시적으로 사용합니다.As shown in the example in the previous section, the ContentControl explicitly uses the detailsProductListingTemplate data template. ListBox 컨트롤은 컬렉션의 AuctionItem 개체를 표시할 때 다음 데이터 템플릿을 암시적으로 사용합니다.The ListBox control implicitly uses the following data template when displaying the AuctionItem objects in the collection.

<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>

DataTemplates를 둘 다 사용하면 결과 UI는 데이터 바인딩이란? 섹션의 UI와 같이 표시됩니다.With the use of those two DataTemplates, the resulting UI is the one shown in the What is data binding section. 스크린샷에 표시된 것처럼 DataTemplates를 사용하면 컨트롤에 데이터를 배치할 수 있을 뿐 아니라 데이터에 대한 눈에 띄는 시각적 개체를 정의할 수도 있습니다.As you can see from that screenshot, in addition to letting you place data in your controls, DataTemplates allow you to define compelling visuals for your data. 예를 들어 DataTrigger는 위의 DataTemplate에서 사용되므로 HighLight 값이 SpecialFeaturesAuctionItem 에는 주황색 테두리와 별모양이 함께 표시됩니다.For example, DataTriggers are used in the above DataTemplate so that AuctionItem s with SpecialFeatures value of HighLight would be displayed with an orange border and a star.

데이터 템플릿에 관한 자세한 내용은 데이터 템플릿 개요를 참조하세요.For more information about data templates, see the Data templating overview.

데이터 유효성 검사Data validation

사용자 입력을 사용하는 대부분 앱에는 사용자가 필요한 정보를 입력했는지 확인할 수 있는 유효성 검사 논리가 있어야 합니다.Most app that take user input need to have validation logic to ensure that the user has entered the expected information. 유효성 검사는 형식, 범위, 서식 또는 기타 앱별 요구 사항에 따라 달라질 수 있습니다.The validation checks can be based on type, range, format, or other app-specific requirements. 이 섹션에서는 WPF에서 데이터 유효성 검사를 사용하는 방법을 설명합니다.This section discusses how data validation works in WPF.

유효성 검사 규칙과 바인딩 연결Associating validation rules with a binding

WPF 데이터 바인딩 모델을 사용하면 ValidationRulesBinding 개체와 연결할 수 있습니다.The WPF data binding model allows you to associate ValidationRules with your Binding object. 예를 들어 다음 예제에서는 TextBoxStartPrice 속성에 바인딩하고 ExceptionValidationRule 개체를 Binding.ValidationRules 속성에 추가합니다.For example, the following example binds a TextBox to a property named StartPrice and adds a ExceptionValidationRule object to the Binding.ValidationRules property.

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

ValidationRule 개체는 속성 값이 유효한지 확인합니다.A ValidationRule object checks whether the value of a property is valid. WPF에는 두 가지 형식의 기본 제공 ValidationRule 개체가 있습니다.WPF has two types of built-in ValidationRule objects:

ValidationRule 클래스에서 파생시키고 Validate 메서드를 구현하는 방식으로 자체 유효성 검사 규칙을 만들 수도 있습니다.You can also create your own validation rule by deriving from the ValidationRule class and implementing the Validate method. 다음 예제에서는 데이터 바인딩이란? 섹션의 Add Product Listing "Start Date" TextBox에서 사용되는 규칙을 보여 줍니다.The following example shows the rule used by the Add Product Listing "Start Date" TextBox from the What is data binding section.

public class FutureDateRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        // Test if date is valid
        if (DateTime.TryParse(value.ToString(), out DateTime date))
        {
            // Date is not in the future, fail
            if (DateTime.Now > date)
                return new ValidationResult(false, "Please enter a date in the future.");
        }
        else
        {
            // Date is not a valid date, fail
            return new ValidationResult(false, "Value is not a valid date.");
        }

        // Date is valid and in the future, pass
        return ValidationResult.ValidResult;
    }
}
Public Class FutureDateRule
    Inherits ValidationRule

    Public Overrides Function Validate(value As Object, cultureInfo As CultureInfo) As ValidationResult

        Dim inputDate As Date

        ' Test if date is valid
        If Date.TryParse(value.ToString, inputDate) Then

            ' Date is not in the future, fail
            If Date.Now > inputDate Then
                Return New ValidationResult(False, "Please enter a date in the future.")
            End If

        Else
            ' // Date Is Not a valid date, fail
            Return New ValidationResult(False, "Value is not a valid date.")
        End If

        ' Date is valid and in the future, pass
        Return ValidationResult.ValidResult

    End Function

End Class

다음 예제와 같이 StartDateEntryForm TextBox는 이 FutureDateRule 을 사용합니다.The StartDateEntryForm TextBox uses this FutureDateRule, as shown in the following example.

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

UpdateSourceTrigger 값은 PropertyChanged이므로 바인딩 엔진은 키 입력이 있을 때마다 소스 값을 업데이트합니다. 즉, 키 입력이 있을 때마다 ValidationRules 컬렉션에서 모든 규칙을 확인합니다.Because the UpdateSourceTrigger value is PropertyChanged, the binding engine updates the source value on every keystroke, which means it also checks every rule in the ValidationRules collection on every keystroke. 이 내용은 유효성 검사 프로세스 섹션에서 자세히 설명합니다.We discuss this further in the Validation Process section.

시각적 피드백 제공Providing visual feedback

사용자가 잘못된 값을 입력할 경우 앱 UI에 오류에 관한 피드백을 표시해야 할 수 있습니다.If the user enters an invalid value, you may want to provide some feedback about the error on the app UI. 해당 피드백을 제공하는 한 가지 방법은 Validation.ErrorTemplate 연결된 속성을 ControlTemplate으로 설정하는 것입니다.One way to provide such feedback is to set the Validation.ErrorTemplate attached property to a custom ControlTemplate. 이전 하위 섹션과 같이 StartDateEntryForm TextBoxvalidationTemplate 이라는 ErrorTemplate을 사용합니다.As shown in the previous subsection, the StartDateEntryForm TextBox uses an ErrorTemplate called validationTemplate. 다음 예제에서는 validationTemplate 의 정의를 보여 줍니다.The following example shows the definition of validationTemplate.

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

AdornedElementPlaceholder 요소는 표시되는 컨트롤을 배치할 위치를 지정합니다.The AdornedElementPlaceholder element specifies where the control being adorned should be placed.

또한 ToolTip을 사용하여 오류 메시지를 표시할 수도 있습니다.In addition, you may also use a ToolTip to display the error message. StartDateEntryFormStartPriceEntryForm TextBox는 둘 다 오류 메시지를 표시하는 ToolTip을 만드는 textStyleTextBox 스타일을 사용합니다.Both the StartDateEntryForm and the StartPriceEntryFormTextBoxes use the style textStyleTextBox, which creates a ToolTip that displays the error message. 다음 예제에서는 textStyleTextBox 의 정의를 보여 줍니다.The following example shows the definition of textStyleTextBox. 바인딩된 요소의 속성에 대한 바인딩 중 하나 이상에서 오류가 발생할 경우 연결된 속성 Validation.HasErrortrue입니다.The attached property Validation.HasError is true when one or more of the bindings on the properties of the bound element are in error.

<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는 유효성 검사 오류가 있는 경우 다음과 같이 표시됩니다.With the custom ErrorTemplate and the ToolTip, the StartDateEntryForm TextBox looks like the following when there is a validation error.

데이터 바인딩 유효성 검사 오류Data binding validation error

Binding에 연결된 유효성 검사 규칙이 있지만 바인딩된 컨트롤에서 ErrorTemplate을 지정하지 않으면 유효성 검사 오류가 있을 경우 이를 사용자에게 알리는 데 기본 ErrorTemplate이 사용됩니다.If your Binding has associated validation rules but you do not specify an ErrorTemplate on the bound control, a default ErrorTemplate will be used to notify users when there is a validation error. 기본 ErrorTemplate은 표시기 레이어에서 빨간색 테두리를 정의하는 컨트롤 템플릿입니다.The default ErrorTemplate is a control template that defines a red border in the adorner layer. 기본 ErrorTemplateToolTip을 사용하면 StartPriceEntryForm TextBox의 UI는 유효성 검사 오류가 발생하는 경우 다음과 같이 표시됩니다.With the default ErrorTemplate and the ToolTip, the UI of the StartPriceEntryForm TextBox looks like the following when there is a validation error.

데이터 바인딩 유효성 검사 오류 기본값Data binding validation error default

대화 상자에서 모든 컨트롤의 유효성을 검사하는 논리를 제공하는 방법의 예제를 보려면 대화 상자 개요에서 사용자 지정 대화 상자 섹션을 참조하세요.For an example of how to provide logic to validate all controls in a dialog box, see the Custom Dialog Boxes section in the Dialog boxes overview.

유효성 검사 프로세스Validation process

유효성 검사는 대개 대상 값이 바인딩 소스 속성에 전송될 때 수행됩니다.Validation usually occurs when the value of a target is transferred to the binding source property. 이 전송은 TwoWayOneWayToSource 바인딩에서 발생합니다.This transfer occurs on TwoWay and OneWayToSource bindings. 다시 말하지만, 소스 업데이트를 트리거하는 항목 섹션에서 설명한 대로 소스 업데이트는 UpdateSourceTrigger 속성의 값에 따라 결정됩니다.To reiterate, what causes a source update depends on the value of the UpdateSourceTrigger property, as described in the What triggers source updates section.

다음 항목은 ‘유효성 검사’ 프로세스를 설명합니다.The following items describe the validation process. 이 프로세스 중에 유효성 검사 오류나 기타 오류가 발생하면 프로세스가 중단됩니다.If a validation error or other type of error occurs at any time during this process, the process is halted:

  1. 바인딩 엔진은 해당 Binding에 대해 ValidationStepRawProposedValue로 설정된 사용자 지정 ValidationRule 개체가 정의되어 있는지 확인합니다. 이 경우 개체 중 하나에서 오류가 발생하거나 모든 개체가 통과할 때까지 각 ValidationRule에서 Validate 메서드를 호출합니다.The binding engine checks if there are any custom ValidationRule objects defined whose ValidationStep is set to RawProposedValue for that Binding, in which case it calls the Validate method on each ValidationRule until one of them runs into an error or until all of them pass.

  2. 그런 다음 바인딩 엔진은 변환기를 호출합니다(있는 경우).The binding engine then calls the converter, if one exists.

  3. 변환기가 성공하면 바인딩 엔진은 해당 Binding에 대해 ValidationStepConvertedProposedValue로 설정된 사용자 지정 ValidationRule 개체가 정의되어 있는지 확인합니다. 이 경우 개체 중 하나에서 오류가 발생하거나 모든 개체가 통과할 때까지 ValidationStepConvertedProposedValue로 설정된 각 ValidationRule에서 Validate 메서드를 호출합니다.If the converter succeeds, the binding engine checks if there are any custom ValidationRule objects defined whose ValidationStep is set to ConvertedProposedValue for that Binding, in which case it calls the Validate method on each ValidationRule that has ValidationStep set to ConvertedProposedValue until one of them runs into an error or until all of them pass.

  4. 바인딩 엔진은 소스 속성을 설정합니다.The binding engine sets the source property.

  5. 바인딩 엔진은 해당 Binding에 대해 ValidationStepUpdatedValue로 설정된 사용자 지정 ValidationRule 개체가 정의되어 있는지 확인합니다. 이 경우 개체 중 하나에서 오류가 발생하거나 모든 개체가 통과할 때까지 ValidationStepUpdatedValue로 설정된 각 ValidationRule에서 Validate 메서드를 호출합니다.The binding engine checks if there are any custom ValidationRule objects defined whose ValidationStep is set to UpdatedValue for that Binding, in which case it calls the Validate method on each ValidationRule that has ValidationStep set to UpdatedValue until one of them runs into an error or until all of them pass. DataErrorValidationRule이 바인딩과 연결되고 해당 ValidationStep이 기본값 UpdatedValue로 설정된 경우 이때 DataErrorValidationRule이 확인됩니다.If a DataErrorValidationRule is associated with a binding and its ValidationStep is set to the default, UpdatedValue, the DataErrorValidationRule is checked at this point. 이때 ValidatesOnDataErrorstrue로 설정된 모든 바인딩이 선택됩니다.At this point any binding that has the ValidatesOnDataErrors set to true is checked.

  6. 바인딩 엔진은 해당 Binding에 대해 ValidationStepCommittedValue로 설정된 사용자 지정 ValidationRule 개체가 정의되어 있는지 확인합니다. 이 경우 개체 중 하나에서 오류가 발생하거나 모든 개체가 통과할 때까지 ValidationStepCommittedValue로 설정된 각 ValidationRule에서 Validate 메서드를 호출합니다.The binding engine checks if there are any custom ValidationRule objects defined whose ValidationStep is set to CommittedValue for that Binding, in which case it calls the Validate method on each ValidationRule that has ValidationStep set to CommittedValue until one of them runs into an error or until all of them pass.

이 프로세스 중에 ValidationRule이 통과하지 못하면 바인딩 엔진은 ValidationError 개체를 만들고 바인딩된 요소의 Validation.Errors 컬렉션에 추가합니다.If a ValidationRule does not pass at any time throughout this process, the binding engine creates a ValidationError object and adds it to the Validation.Errors collection of the bound element. 바인딩 엔진은 특정 단계에서 ValidationRule 개체를 실행하기 전에 해당 단계 중에 바인딩된 요소의 Validation.Errors 연결된 속성에 추가된 모든 ValidationError를 제거합니다.Before the binding engine runs the ValidationRule objects at any given step, it removes any ValidationError that was added to the Validation.Errors attached property of the bound element during that step. 예를 들어 ValidationStepUpdatedValue로 설정된 ValidationRule이 실패한 경우 다음에 유효성 검사 프로세스가 수행될 때 바인딩 엔진은 ValidationStepUpdatedValue로 설정된 ValidationRule을 호출하기 직전에 해당 ValidationError를 제거합니다.For example, if a ValidationRule whose ValidationStep is set to UpdatedValue failed, the next time the validation process occurs, the binding engine removes that ValidationError immediately before it calls any ValidationRule that has ValidationStep set to UpdatedValue.

Validation.Errors가 비어 있지 않으면 요소의 Validation.HasError 연결된 속성은 true로 설정됩니다.When Validation.Errors is not empty, the Validation.HasError attached property of the element is set to true. 또한 BindingNotifyOnValidationError 속성이 true로 설정된 경우 바인딩 엔진은 요소에서 Validation.Error 연결된 이벤트를 발생시킵니다.Also, if the NotifyOnValidationError property of the Binding is set to true, then the binding engine raises the Validation.Error attached event on the element.

한쪽 방향으로(대상에서 소스로 또는 소스에서 대상으로) 유효한 값이 전송되면 Validation.Errors 연결된 속성이 지워집니다.Also note that a valid value transfer in either direction (target to source or source to target) clears the Validation.Errors attached property.

바인딩에 연결된 ExceptionValidationRule이 있거나 ValidatesOnExceptions 속성이 true로 설정되고 바인딩 엔진이 소스를 설정할 때 예외가 throw된 경우 바인딩 엔진은 UpdateSourceExceptionFilter가 있는지 확인합니다.If the binding either has an ExceptionValidationRule associated with it, or had the ValidatesOnExceptions property is set to true and an exception is thrown when the binding engine sets the source, the binding engine checks to see if there is a UpdateSourceExceptionFilter. UpdateSourceExceptionFilter 콜백을 사용하여 예외를 처리하기 위한 사용자 지정 처리기를 제공하는 옵션이 있습니다.You have the option to use the UpdateSourceExceptionFilter callback to provide a custom handler for handling exceptions. UpdateSourceExceptionFilterBinding에 지정되지 않은 경우 바인딩 엔진은 예외가 있는 ValidationError를 만들고 바인딩된 요소의 Validation.Errors 컬렉션에 추가합니다.If an UpdateSourceExceptionFilter is not specified on the Binding, the binding engine creates a ValidationError with the exception and adds it to the Validation.Errors collection of the bound element.

디버깅 메커니즘Debugging mechanism

바인딩 관련 개체에서 PresentationTraceSources.TraceLevel 연결된 속성을 설정하여 특정 바인딩 상태에 대한 정보를 받을 수 있습니다.You can set the attached property PresentationTraceSources.TraceLevel on a binding-related object to receive information about the status of a specific binding.

참조See also