이 문서에서는 Microsoft.UI.Xaml.Data 네임스페이스에 상주하는 API에 대한 Windows 앱 SDK 데이터 바인딩 기능을 설명합니다.
비고
이 항목에서는 데이터 바인딩 기능에 대해 자세히 설명합니다. 짧고 실용적인 소개는 데이터 바인딩 개요를 참조하세요.
중요 API
소개
데이터 바인딩은 앱의 UI에서 데이터를 표시하고 필요에 따라 해당 데이터와 동기화 상태를 유지하는 방법입니다. 데이터 바인딩을 사용하면 데이터의 문제를 UI와 분리할 수 있으며, 이로 인해 앱의 가독성, 테스트 가능성 및 유지 관리 효율성이 향상되고 더 간단한 개념적 모델이 생성됩니다.
데이터 바인딩을 사용하여 UI가 처음 표시되면 데이터 원본의 값을 표시하지만 해당 값의 변경 내용에 응답하지 않을 수 있습니다. 일회성 이라는 바인딩 모드이며 런타임 동안 변경되지 않는 값에 적합합니다. 또는 값을 "관찰"하고 변경 시 UI를 업데이트하도록 선택할 수 있습니다. 이 모드는 단방향이라고 하며 읽기 전용 데이터에 적합합니다. 궁극적으로 사용자가 UI의 값에 적용한 변경 내용이 자동으로 데이터 원본으로 다시 푸시되도록 관찰하고 업데이트하도록 선택할 수 있습니다. 이 모드는 양방향이라고 하며 읽기/쓰기 데이터에 적합합니다. 다음은 몇 가지 예입니다.
- 일회성 모드를 사용하여 이미지를 현재 사용자의 사진에 바인딩할 수 있습니다.
- 단방향 모드를 사용하여 ListView 를 신문 섹션별로 그룹화된 실시간 뉴스 기사 모음에 바인딩할 수 있습니다.
- 양방향 모드를 사용하여 텍스트 상자를 양식의 고객 이름에 바인딩할 수 있습니다.
모드와 관계없이 두 종류의 바인딩이 있으며 둘 다 일반적으로 UI 태그에서 선언됩니다.
{x:Bind} 태그 확장 또는 {Binding} 태그 확장을 사용하도록 선택할 수 있습니다. 동일한 UI 요소에서도 동일한 앱에서 두 항목의 혼합을 사용할 수도 있습니다.
{x:Bind}
는 Windows 10용 UWP의 새로운 기능이며 성능이 향상되었습니다. 이 항목에 설명된 모든 세부 정보는 명시적으로 달리 말하지 않는 한 두 종류의 바인딩에 모두 적용됩니다.
{x:Bind}를 보여 주는 UWP 샘플 앱
{Binding}을(를) 보여 주는 UWP 샘플 앱
- UWP Bookstore1 앱을 다운로드합니다.
- Bookstore2 앱을 다운로드합니다.
모든 바인딩에는 이러한 부분이 포함됩니다.
- 바인딩 소스입니다. 바인딩에 대한 데이터의 원본이며 UI에 표시할 값이 있는 멤버가 있는 모든 클래스의 인스턴스일 수 있습니다.
- 바인딩 대상입니다. 데이터를 표시하는 UI에서 FrameworkElement의 DependencyProperty입니다.
- 바인딩 개체입니다. 원본에서 대상으로, 필요에 따라 대상에서 원본으로 데이터 값을 전송하는 요소입니다. 바인딩 개체는 {x:Bind} 또는 {Binding} 태그 확장에서 XAML 로드 시간에 만들어집니다.
다음 섹션에서는 바인딩 원본, 바인딩 대상 및 바인딩 개체를 자세히 살펴보겠습니다. 또한 단추의 콘텐츠를 명명NextButtonText
HostViewModel
된 클래스에 속하는 문자열 속성에 바인딩하는 예제와 섹션을 연결합니다.
바인딩 원본
다음은 바인딩 소스로 사용할 수 있는 클래스의 매우 기본적인 구현입니다.
public class HostViewModel
{
public HostViewModel()
{
NextButtonText = "Next";
}
public string NextButtonText { get; set; }
}
해당 구현 HostViewModel
및 해당 속성 NextButtonText
은 일회성 바인딩에만 적합합니다. 그러나 단방향 및 양방향 바인딩은 매우 일반적이며 이러한 종류의 바인딩에서는 바인딩 원본의 데이터 값 변경에 따라 UI가 자동으로 업데이트됩니다. 이러한 종류의 바인딩이 올바르게 작동하려면 바인딩 개체에 대한 바인딩 소스를 관찰할 수 있도록 해야 합니다. 따라서 이 예제에서 단방향 또는 양방향으로 속성에 NextButtonText
바인딩하려는 경우 런타임에 해당 속성 값에 대해 발생하는 모든 변경 내용을 바인딩 개체에서 관찰할 수 있어야 합니다.
이 작업을 수행하는 한 가지 방법은 DependencyObject에서 바인딩 소스를 나타내는 클래스를 파생시키고 DependencyProperty를 통해 데이터 값을 노출하는 것입니다. 이것이 FrameworkElement 를 관찰하는 방법입니다. A FrameworkElement
는 올바른 바인딩 원본입니다.
클래스를 관찰할 수 있도록 하는 보다 간단한 방법과 기본 클래스가 이미 있는 클래스에 필요한 방법은 System.ComponentModel.INotifyPropertyChanged를 구현하는 것입니다. 실제로는 이름이 지정된 PropertyChanged
단일 이벤트를 구현하는 작업만 포함됩니다. 사용 HostViewModel
예는 다음과 같습니다.
...
using System.ComponentModel;
using System.Runtime.CompilerServices;
...
public class HostViewModel : INotifyPropertyChanged
{
private string nextButtonText;
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public HostViewModel()
{
NextButtonText = "Next";
}
public string NextButtonText
{
get { return nextButtonText; }
set
{
nextButtonText = value;
OnPropertyChanged();
}
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
// Raise the PropertyChanged event, passing the name of the property whose value has changed.
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
NextButtonText
이제 속성을 관찰할 수 있습니다. 해당 속성에 대한 단방향 또는 양방향 바인딩을 작성할 때(나중에 방법을 보여 드리겠습니다) 결과 바인딩 개체가 이벤트를 구독합니다 PropertyChanged
. 해당 이벤트가 발생하면 바인딩 개체의 처리기는 변경된 속성의 이름을 포함하는 인수를 받습니다. 이것이 바인딩 개체가 다시 읽고 이동해야 하는 속성의 값을 파악하는 방법입니다.
위에 표시된 패턴을 여러 번 구현할 필요가 없도록 C#을 사용하는 경우 BindableBase
샘플("Common" 폴더)에서 찾을 수 있는 기본 클래스에서 파생할 수 있습니다. 다음은 모양에 대한 예입니다.
public class HostViewModel : BindableBase
{
private string nextButtonText;
public HostViewModel()
{
NextButtonText = "Next";
}
public string NextButtonText
{
get { return nextButtonText; }
set { SetProperty(ref nextButtonText, value); }
}
}
PropertyChanged
String.Empty 인수를 사용하여 이벤트를 발생하거나 null
개체의 모든 비 인덱서 속성을 다시 읽어야 했음을 나타냅니다. 특정 인덱서(인덱서가 인덱스 값인 경우)에 대해 "Item[indexer]" 인수를 사용하거나 모든 인덱서에 대해 "Item[]" 값을 사용하여 개체의 인덱서 속성이 변경되었음을 나타내는 이벤트를 발생할 수 있습니다.
바인딩 원본은 속성에 데이터가 포함된 단일 개체 또는 개체 컬렉션으로 처리할 수 있습니다. C# 코드에서는 List<T> 를 구현하는 개체에 일회성 바인딩을 사용하여 런타임에 변경되지 않는 컬렉션을 표시할 수 있습니다. 관찰 가능한 컬렉션(항목이 컬렉션에 추가되고 컬렉션에서 제거되는 경우 관찰)의 경우 단방향으로 ObservableCollection<T> 에 바인딩합니다. 사용자 고유의 컬렉션 클래스에 바인딩하려면 다음 표의 지침을 사용합니다.
증분 로드를 사용하여 목록 컨트롤을 임의로 큰 데이터 원본에 바인딩하고 고성능을 달성할 수 있습니다. 예를 들어 모든 결과를 한 번에 로드하지 않고도 목록 컨트롤을 Bing 이미지 쿼리 결과에 바인딩할 수 있습니다. 대신 일부 결과만 즉시 로드하고 필요에 따라 추가 결과를 로드합니다. 증분 로드를 지원하려면 컬렉션 변경 알림을 지원하는 데이터 원본에서 ISupportIncrementalLoading 을 구현해야 합니다. 데이터 바인딩 엔진이 더 많은 데이터를 요청하는 경우 데이터 원본은 적절한 요청을 수행하고 결과를 통합한 다음 UI를 업데이트하기 위해 적절한 알림을 보내야 합니다.
바인딩 대상
아래 Button.Content
두 예제에서 속성은 바인딩 대상이며 해당 값은 바인딩 개체를 선언하는 태그 확장으로 설정됩니다. 첫 번째 {x:Bind} 가 표시되고 {Binding}이 표시됩니다. 태그에서 바인딩을 선언하는 것이 일반적인 경우입니다(편리하고 읽기 가능하며 도구 가능). 그러나 태그를 방지하고 필요한 경우 대신 바인딩 클래스의 인스턴스를 명령적으로(프로그래밍 방식으로) 만들 수 있습니다.
<Button Content="{x:Bind ...}" ... />
<Button Content="{Binding ...}" ... />
C++/WinRT를 사용하는 경우 {Binding} 태그 확장을 사용하려는 런타임 클래스에 BindableAttribute 특성을 추가해야 합니다.
중요합니다
C++/WinRT를 사용하는 경우 Windows 앱 SDK에서 BindableAttribute 특성을 사용할 수 있습니다. 이 특성이 없으면 {Binding} 태그 확장을 사용하려면 ICustomPropertyProvider 및 ICustomProperty 인터페이스를 구현해야 합니다.
{x:Bind}를 사용하여 선언된 바인딩 개체
{x:Bind} 태그를 작성하기 전에 수행해야 하는 한 단계가 있습니다. 태그 페이지를 나타내는 클래스에서 바인딩 소스 클래스를 노출해야 합니다. 이 경우 속성(이 경우 형식 HostViewModel
)을 창 클래스에 MainWindow
추가하여 이 작업을 수행합니다.
namespace DataBindingInDepth
{
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
ViewModel = new HostViewModel();
}
public HostViewModel ViewModel { get; set; }
}
}
이렇게 하면 이제 바인딩 개체를 선언하는 태그를 자세히 살펴볼 수 있습니다. 아래 예제에서는 앞에서 "바인딩 대상" 섹션에서 사용한 것과 동일한 Button.Content
바인딩 대상을 사용하며 속성에 바인딩되는 것을 HostViewModel.NextButtonText
보여 드립니다.
<!-- MainWindow.xaml -->
<Window x:Class="DataBindingInDepth.MainWindow" ... >
<Button Content="{x:Bind Path=ViewModel.NextButtonText, Mode=OneWay}" ... />
</Window>
에 대해 지정하는 값을 확인합니다 Path
. 이 값은 창 자체의 컨텍스트에서 해석되며, 이 경우 경로는 페이지에 방금 추가 ViewModel
한 속성을 참조하여 MainWindow
시작됩니다. 해당 속성은 인스턴스를 HostViewModel
반환하므로 해당 개체에 점을 적용 하여 속성에 HostViewModel.NextButtonText
액세스할 수 있습니다. {Mode
기본값을 일회성으로 재정의하도록 지정합니다.
Path 속성은 중첩 속성, 연결된 속성, 정수 및 문자열 인덱서에 바인딩하기 위한 다양한 구문 옵션을 지원합니다. 자세한 내용은 속성 경로 구문을 참조하세요. 문자열 인덱서에 바인딩하면 ICustomPropertyProvider를 구현하지 않고도 동적 속성에 바인딩할 수 있습니다. 다른 설정은 {x:Bind} 태그 확장을 참조하세요.
속성이 HostViewModel.NextButtonText
실제로 관찰 가능함을 보여 주려면 단추에 이벤트 처리기를 추가하고 Click
값을 HostViewModel.NextButtonText
업데이트합니다. 단추를 빌드, 실행 및 클릭하여 단추 Content
업데이트 값을 확인합니다.
// MainWindow.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
ViewModel.NextButtonText = "Updated Next button text";
}
비고
TextBox.Text에 대한 변경 내용은 TextBox가 포커스를 잃을 때 양방향 바인딩된 원본으로 전송되며, 모든 사용자 키 입력 후에는 전송되지 않습니다.
DataTemplate 및 x:DataType
DataTemplate 내에서(항목 템플릿, 콘텐츠 템플릿 또는 헤더 템플릿으로 사용되든) 값 Path
은 창의 컨텍스트에서 해석되지 않고 템플릿을 지정하는 데이터 개체의 컨텍스트에서 해석됩니다. 컴파일 시간에 {x:Bind}
바인딩의 유효성을 검사하고 효율적인 코드를 생성할 수 있도록 데이터 템플릿에서 사용할 DataTemplate
때는 해당 데이터 개체의 형식을 사용하여 x:DataType
선언해야 합니다. 아래에 제공된 예제는 개체 컬렉션에 ItemTemplate
바인딩된 항목 컨트롤의 SampleDataGroup
예제로 사용할 수 있습니다.
<DataTemplate x:Key="SimpleItemTemplate" x:DataType="data:SampleDataGroup">
<StackPanel Orientation="Vertical" Height="50">
<TextBlock Text="{x:Bind Title}"/>
<TextBlock Text="{x:Bind Description}"/>
</StackPanel>
</DataTemplate>
Path의 약한 형식의 개체
예를 들어 이름이 SampleDataGroup
지정된 Title
문자열 속성을 구현하는 형식을 사용하는 것이 좋습니다. 형식이지만 실제로 인스턴스를 반환하는 속성MainWindow.SampleDataGroupAsObject
object
이 SampleDataGroup
있습니다. 형식<TextBlock Text="{x:Bind SampleDataGroupAsObject.Title}"/>
에서 속성을 찾을 수 없으므로 Title
바인딩 object
으로 인해 컴파일 오류가 발생합니다. 이에 대한 해결 방법은 다음과 Path
같이 구문에 캐스트를 <TextBlock Text="{x:Bind ((data:SampleDataGroup)SampleDataGroupAsObject).Title}"/>
추가하는 것입니다. 다음은 다음과 같이 Element
선언되지만 실제로는 다음과 object
같은 또 다른 예 TextBlock
입니다<TextBlock Text="{x:Bind Element.Text}"/>
. 그리고 캐스트는 문제를 해결 : <TextBlock Text="{x:Bind ((TextBlock)Element).Text}"/>
.
데이터가 비동기적으로 로드되는 경우
지원할 {x:Bind}
코드는 창의 부분 클래스에서 컴파일 시간에 생성됩니다. 이러한 파일은 (C#의 경우) obj
같은 이름으로 폴더에서 <view name>.g.cs
찾을 수 있습니다. 생성된 코드에는 창의 Loading 이벤트에 대한 처리기가 포함되며, 해당 처리기는 창의 바인딩을 나타내는 생성된 클래스에서 메서드를 호출 Initialize
합니다.
Initialize
차례로 바인딩 원본과 대상 간에 데이터 이동을 시작하기 위해 호출 Update
합니다.
Loading
는 창 또는 사용자 컨트롤의 첫 번째 측정값 전달 바로 전에 발생합니다. 따라서 데이터가 비동기적으로 로드되는 경우 호출될 때까지 Initialize
준비되지 않을 수 있습니다. 따라서 데이터를 로드한 후에는 호출 this.Bindings.Update();
을 통해 일회성 바인딩을 강제로 초기화할 수 있습니다. 비동기적으로 로드된 데이터에 대해 일회성 바인딩만 필요한 경우 단방향 바인딩을 사용하고 변경 내용을 수신 대기하는 것보다 이러한 방식으로 초기화하는 것이 훨씬 저렴합니다. 데이터가 세분화된 변경을 거치지 않고 특정 작업의 일부로 업데이트될 가능성이 있는 경우 바인딩을 한 번 만들고 언제든지 호출을 통해 수동으로 업데이트할 Update
수 있습니다.
비고
{x:Bind}
는 JSON 개체의 사전 구조 탐색이나 오리 입력과 같은 런타임에 바인딩된 시나리오에 적합하지 않습니다. "오리 입력"은 속성 이름에 어휘 일치를 기반으로 입력의 약한 형태입니다 (에서와 같이, "그것은 걷고, 수영하고, 오리처럼 quacks 경우, 그것은 오리입니다"). duck 입력을 사용하면 속성에 대한 Age
바인딩이 개체 또는 Person
개체에 동일하게 충족 Wine
됩니다(이러한 형식에 각각 Age
속성이 있다고 가정). 이러한 시나리오에서는 태그 확장을 사용합니다 {Binding}
.
{Binding}을(를) 사용하여 선언된 바인딩 개체
C++/WinRT를 사용하는 경우 {Binding} 태그 확장을 사용하려면 바인딩하려는 런타임 클래스에 BindableAttribute 특성을 추가해야 합니다. {x:Bind}를 사용하려면 해당 특성이 필요하지 않습니다.
// HostViewModel.idl
// Add this attribute:
[Microsoft.UI.Xaml.Data.Bindable]
runtimeclass HostViewModel : Microsoft.UI.Xaml.Data.INotifyPropertyChanged
{
HostViewModel();
String NextButtonText;
}
중요합니다
C++/WinRT를 사용하는 경우 Windows 앱 SDK에서 BindableAttribute 특성을 사용할 수 있습니다. 이 특성이 없으면 {Binding} 태그 확장을 사용하려면 ICustomPropertyProvider 및 ICustomProperty 인터페이스를 구현해야 합니다.
{Binding} 은 기본적으로 태그 창의 DataContext 에 바인딩한다고 가정합니다. 따라서 창의 DataContext
인스턴스를 바인딩 소스 클래스의 인스턴스로 설정합니다(이 경우 형식 HostViewModel
). 아래 예제에서는 바인딩 개체를 선언하는 태그를 보여 줍니다. 앞에서 "바인딩 대상" 섹션에서 사용한 것과 동일한 Button.Content
바인딩 대상을 사용하고 속성에 바인딩합니다 HostViewModel.NextButtonText
.
<Window xmlns:viewmodel="using:DataBindingInDepth" ... >
<Window.DataContext>
<viewmodel:HostViewModel x:Name="viewModelInDataContext"/>
</Window.DataContext>
...
<Button Content="{Binding Path=NextButtonText}" ... />
</Window>
// MainWindow.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
viewModelInDataContext.NextButtonText = "Updated Next button text";
}
에 대해 지정하는 값을 확인합니다 Path
. 이 값은 이 예제에서 인스턴스로 설정된 창의 HostViewModel
컨텍스트에서 해석됩니다. 경로는 속성을 참조합니다 HostViewModel.NextButtonText
. 여기서는 단방향Mode
기본값이 작동하므로 생략할 수 있습니다.
UI 요소에 대한 DataContext 의 기본값은 해당 부모의 상속된 값입니다. 물론 명시적으로 설정 DataContext
하여 기본값을 재정의할 수 있으며, 이는 기본적으로 자식에 의해 상속됩니다. 요소에 명시적으로 설정하는 DataContext
것은 동일한 소스를 사용하는 여러 바인딩을 사용하려는 경우에 유용합니다.
바인딩 개체에는 Source
기본적으로 바인딩이 선언된 UI 요소의 DataContext 로 설정되는 속성이 있습니다. 바인딩을 설정하거나 Source
명시적으로 설정RelativeSource
ElementName
하여 이 기본값을 재정의할 수 있습니다(자세한 내용은 {Binding} 참조).
DataTemplate 내에서 DataContext는 템플릿을 만드는 데이터 개체로 자동으로 설정됩니다. 아래에 제공된 예제는 문자열 속성이 명명 ItemTemplate
되고 있는 모든 형식의 컬렉션에 바인딩된 항목 컨트롤의 예제로 Title
사용할 수 있습니다Description
.
<DataTemplate x:Key="SimpleItemTemplate">
<StackPanel Orientation="Vertical" Height="50">
<TextBlock Text="{Binding Title}"/>
<TextBlock Text="{Binding Description"/>
</StackPanel>
</DataTemplate>
비고
기본적으로 TextBox.Text 에 대한 변경 내용은 TextBox 에 포커스가 끊어지면 양방향 바인딩된 원본으로 전송됩니다. 모든 사용자 키 입력 후에 변경 내용이 전송되도록 하려면 태그의 바인딩으로 설정합니다 UpdateSourceTrigger
PropertyChanged
. 으로 설정 UpdateSourceTrigger
하여 변경 내용이 원본으로 전송되는 시기를 완전히 제어할 수도 있습니다 Explicit
. 그런 다음 텍스트 상자(일반적으로 TextBox.TextChanged)에서 이벤트를 처리하고, 대상에서 GetBindingExpression을 호출하여 BindingExpression 개체를 가져오고, 마지막으로 BindingExpression.UpdateSource 를 호출하여 데이터 원본을 프로그래밍 방식으로 업데이트합니다.
Path 속성은 중첩 속성, 연결된 속성, 정수 및 문자열 인덱서에 바인딩하기 위한 다양한 구문 옵션을 지원합니다. 자세한 내용은 속성 경로 구문을 참조하세요. 문자열 인덱서에 바인딩하면 ICustomPropertyProvider를 구현하지 않고도 동적 속성에 바인딩할 수 있습니다. ElementName 속성은 요소-요소 바인딩에 유용합니다. RelativeSource 속성에는 여러 가지 용도가 있으며, 그 중 하나는 ControlTemplate 내의 템플릿 바인딩에 대한 보다 강력한 대안입니다. 다른 설정은 {Binding} 태그 확장 및 Binding 클래스를 참조하세요.
원본과 대상이 동일한 형식이 아니면 어떻게 해야 할까요?
부울 속성의 값을 기반으로 UI 요소의 표시 여부를 제어하거나 숫자 값의 범위 또는 추세 함수인 색으로 UI 요소를 렌더링하려는 경우 또는 문자열을 예상하는 UI 요소 속성에 날짜 및/또는 시간 값을 표시하려는 경우 그런 다음 값을 한 형식에서 다른 형식으로 변환해야 합니다. 올바른 솔루션이 바인딩 소스 클래스에서 올바른 형식의 다른 속성을 노출하고 변환 논리를 캡슐화하고 테스트 가능한 상태로 유지하는 경우가 있습니다. 그러나 원본 및 대상 속성의 많은 수 또는 큰 조합이 있는 경우 유연하거나 확장성이 없습니다. 이 경우 다음과 같은 몇 가지 옵션이 있습니다.
- 사용하는
{x:Bind}
경우 함수에 직접 바인딩하여 변환을 수행할 수 있습니다. - 또는 변환을 수행하도록 설계된 개체인 값 변환기를 지정할 수 있습니다.
값 변환기
다음은 DateTime 값을 월이 포함된 값으로 변환하는 일회용 또는 단방향 바인딩에 string
적합한 값 변환기입니다. 이 클래스는 IValueConverter를 구현합니다.
public class DateToStringConverter : IValueConverter
{
// Define the Convert method to convert a DateTime value to
// a month string.
public object Convert(object value, Type targetType,
object parameter, string language)
{
// value is the data from the source object.
DateTime thisDate = (DateTime)value;
int monthNum = thisDate.Month;
string month;
switch (monthNum)
{
case 1:
month = "January";
break;
case 2:
month = "February";
break;
default:
month = "Month not found";
break;
}
// Return the value to pass to the target.
return month;
}
// ConvertBack is not implemented for a OneWay binding.
public object ConvertBack(object value, Type targetType,
object parameter, string language)
{
throw new NotImplementedException();
}
}
바인딩 개체 태그에서 해당 값 변환기를 사용하는 방법은 다음과 같습니다.
<UserControl.Resources>
<local:DateToStringConverter x:Key="Converter1"/>
</UserControl.Resources>
...
<TextBlock Grid.Column="0"
Text="{x:Bind ViewModel.Month, Converter={StaticResource Converter1}}"/>
<TextBlock Grid.Column="0"
Text="{Binding Month, Converter={StaticResource Converter1}}"/>
바인딩에 대해 Converter 매개 변수가 정의된 경우 바인딩 엔진은 Convert 및 ConvertBack 메서드를 호출합니다. 원본에서 데이터를 전달하면 바인딩 엔진이 반환된 데이터를 호출 Convert
하고 대상에 전달합니다. 데이터가 대상에서 전달되면(양방향 바인딩의 경우) 바인딩 엔진은 반환된 데이터를 호출 ConvertBack
하고 원본에 전달합니다.
변환기에서는 변환에 사용할 언어를 지정할 수 있는 ConverterLanguage와 변환 논리에 대한 매개 변수를 전달할 수 있는 ConverterParameter 등의 선택적 매개 변수도 있습니다. 변환기 매개 변수를 사용하는 예제는 IValueConverter를 참조하세요.
비고
변환에 오류가 있는 경우 예외를 throw하지 마세요. 대신 DependencyProperty.UnsetValue를 반환하여 데이터 전송을 중지합니다.
바인딩 소스를 확인할 수 없을 때마다 사용할 기본값을 표시하려면 태그에서 FallbackValue
바인딩 개체의 속성을 설정합니다. 변환 및 서식 지정 오류를 처리하는 데 유용합니다. 또한 다른 유형의 바인딩된 컬렉션에 있는 모든 개체에 존재하지 않을 수 있는 소스 속성에 바인딩하는 것도 유용합니다.
텍스트 컨트롤을 문자열이 아닌 값에 바인딩하는 경우 데이터 바인딩 엔진은 값을 문자열로 변환합니다. 값이 참조 형식인 경우 데이터 바인딩 엔진은 ICustomPropertyProvider.GetStringRepresentation 또는 IStringable.ToString 을 호출하여 문자열 값을 검색하고, 그렇지 않으면 Object.ToString을 호출합니다. 그러나 바인딩 엔진은 기본 클래스 구현을 숨기는 모든 ToString
구현을 무시합니다. 서브클래스 구현은 대신 기본 클래스 ToString
메서드를 재정의해야 합니다. 마찬가지로, 네이티브 언어에서 모든 관리되는 개체 는 ICustomPropertyProvider 및 IStringable을 구현하는 것처럼 보입니다. 그러나 모든 호출 GetStringRepresentation
은 IStringable.ToString
해당 메서드의 재정의로 라우팅 Object.ToString
되고 기본 클래스 구현을 숨기는 새 ToString
구현으로는 절대로 라우팅되지 않습니다.
비고
Windows 커뮤니티 도구 키트는 BoolToVisibilityConverter를 제공합니다. 변환기는 열거형 값 true
Visible
에 false
매핑 Collapsed
되므로 변환기를 만들지 않고 속성을 부울에 바인딩 Visibility
할 수 있습니다. 변환기를 사용하려면 프로젝트에서 CommunityToolkit.WinUI.Converters NuGet 패키지를 추가해야 합니다.
{x:Bind}의 함수 바인딩
{x:Bind}
를 사용하면 바인딩 경로의 마지막 단계가 함수가 될 수 있습니다. 변환을 수행하고 둘 이상의 속성에 의존하는 바인딩을 수행하는 데 사용할 수 있습니다.
x:Bind의 함수 참조
요소-요소 바인딩
한 XAML 요소의 속성을 다른 XAML 요소의 속성에 바인딩할 수 있습니다. 태그에서 표시되는 방식의 예는 다음과 같습니다.
<TextBox x:Name="myTextBox" />
<TextBlock Text="{x:Bind myTextBox.Text, Mode=OneWay}" />
{x:Bind}가 있는 리소스 사전
{x:Bind} 태그 확장은 코드 생성에 따라 달라지므로 생성된 코드를 초기화하기 위해 호출 InitializeComponent
하는 생성자가 포함된 코드 숨김 파일이 필요합니다. 파일 이름을 참조하는 대신 해당 형식을 InitializeComponent
인스턴스화하여 리소스 사전을 다시 사용합니다. 기존 리소스 사전이 있고 이 사전에서 사용 {x:Bind}
하려는 경우 수행할 작업의 예는 다음과 같습니다.
<!-- TemplatesResourceDictionary.xaml -->
<ResourceDictionary
x:Class="ExampleNamespace.TemplatesResourceDictionary"
.....
xmlns:examplenamespace="using:ExampleNamespace">
<DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
<Grid>
<TextBlock Text="{x:Bind Name}"/>
</Grid>
</DataTemplate>
</ResourceDictionary>
// TemplatesResourceDictionary.xaml.cs
using Microsoft.UI.Xaml.Data;
namespace ExampleNamespace
{
public partial class TemplatesResourceDictionary
{
public TemplatesResourceDictionary()
{
InitializeComponent();
}
}
}
<!-- MainWindow.xaml -->
<Window x:Class="ExampleNamespace.MainWindow"
....
xmlns:examplenamespace="using:ExampleNamespace">
<Window.Resources>
<ResourceDictionary>
....
<ResourceDictionary.MergedDictionaries>
<examplenamespace:TemplatesResourceDictionary/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
</Window>
재사용 가능한 스타일에서 {x:Bind} 및 {Binding} 혼합
이전 예제에서는 DataTemplates에서 사용하는 {x:Bind}
것으로 나타났지만, 다시 사용할 수 있는 스타일을 만들어 태그 확장과 {Binding}
태그 확장을 모두 {x:Bind}
결합할 수도 있습니다. 이 기능은 사용 중인 컴파일 시간 알려진 값에 일부 속성을 바인딩하고 다른 속성을 사용하여 {x:Bind}
{Binding}
런타임 DataContext 값에 바인딩하려는 경우에 유용합니다.
다음은 두 바인딩 방법을 모두 사용하는 재사용 가능한 단추 스타일을 만드는 방법을 보여 주는 예제입니다.
TemplatesResourceDictionary.xaml
<!-- TemplatesResourceDictionary.xaml -->
<ResourceDictionary
x:Class="ExampleNamespace.TemplatesResourceDictionary"
.....
xmlns:examplenamespace="using:ExampleNamespace">
<!-- DataTemplate using x:Bind -->
<DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
<Grid>
<TextBlock Text="{x:Bind Name}"/>
</Grid>
</DataTemplate>
<!-- Style that mixes x:Bind and Binding -->
<Style x:Key="CustomButtonStyle" TargetType="Button">
<Setter Property="Background" Value="{Binding ButtonBackgroundBrush}"/>
<Setter Property="Foreground" Value="{Binding ButtonForegroundBrush}"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="RootBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<!-- x:Bind to a static property or page-level property -->
<Ellipse Width="8" Height="8"
Fill="{x:Bind DefaultIndicatorBrush}"
Margin="0,0,8,0"/>
<!-- Binding to DataContext -->
<ContentPresenter x:Name="ContentPresenter"
Content="{TemplateBinding Content}"
Foreground="{TemplateBinding Foreground}"
FontSize="{TemplateBinding FontSize}"/>
</StackPanel>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<!-- Binding to DataContext for hover color -->
<Setter Target="RootBorder.Background"
Value="{Binding ButtonHoverBrush}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<!-- x:Bind to a compile-time known resource -->
<Setter Target="RootBorder.Background"
Value="{x:Bind DefaultPressedBrush}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
TemplatesResourceDictionary.xaml.cs
// TemplatesResourceDictionary.xaml.cs
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Media;
namespace ExampleNamespace
{
public partial class TemplatesResourceDictionary
{
public TemplatesResourceDictionary()
{
InitializeComponent();
}
// Properties for x:Bind - these are compile-time bound
public SolidColorBrush DefaultIndicatorBrush { get; } =
new SolidColorBrush(Colors.Green);
public SolidColorBrush DefaultPressedBrush { get; } =
new SolidColorBrush(Colors.DarkGray);
}
}
런타임 값을 제공하는 ViewModel을 사용하는 MainWindow.xaml의 사용량:
<!-- MainWindow.xaml -->
<Window x:Class="ExampleNamespace.MainWindow"
....
xmlns:examplenamespace="using:ExampleNamespace">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<examplenamespace:TemplatesResourceDictionary/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.DataContext>
<examplenamespace:ButtonThemeViewModel/>
</Grid.DataContext>
<StackPanel Margin="20">
<!-- These buttons use the mixed binding style -->
<Button Content="Save" Style="{StaticResource CustomButtonStyle}"/>
<Button Content="Cancel" Style="{StaticResource CustomButtonStyle}"/>
</StackPanel>
</Grid>
</Window>
ButtonThemeViewModel.cs(런타임 바인딩 값을 제공하는 DataContext):
using System.ComponentModel;
using Microsoft.UI;
using Microsoft.UI.Xaml.Media;
namespace ExampleNamespace
{
public class ButtonThemeViewModel : INotifyPropertyChanged
{
private SolidColorBrush _buttonBackgroundBrush = new SolidColorBrush(Colors.LightBlue);
private SolidColorBrush _buttonForegroundBrush = new SolidColorBrush(Colors.DarkBlue);
private SolidColorBrush _buttonHoverBrush = new SolidColorBrush(Colors.LightCyan);
public SolidColorBrush ButtonBackgroundBrush
{
get => _buttonBackgroundBrush;
set
{
_buttonBackgroundBrush = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonBackgroundBrush)));
}
}
public SolidColorBrush ButtonForegroundBrush
{
get => _buttonForegroundBrush;
set
{
_buttonForegroundBrush = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonForegroundBrush)));
}
}
public SolidColorBrush ButtonHoverBrush
{
get => _buttonHoverBrush;
set
{
_buttonHoverBrush = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonHoverBrush)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
이 예제에서:
-
{Binding}
는 DataContext(ButtonBackgroundBrush, ButtonForegroundBrush, ButtonHoverBrush)에 의존하는 속성에 사용됩니다. -
{x:Bind}
는 컴파일 시간이 알려져 있고 ResourceDictionary 자체에 속하는 속성에 사용됩니다(DefaultIndicatorBrush, DefaultPressedBrush). - 스타일을 다시 사용할 수 있으며 모든 단추에 적용할 수 있습니다.
- 런타임 테마는 DataContext를 통해 가능하지만 정적 요소에 대한 성능의
{x:Bind}
이점을 활용할 수 있습니다.
이벤트 바인딩 및 ICommand
{x:Bind} 는 이벤트 바인딩이라는 기능을 지원합니다. 이 기능을 사용하면 바인딩을 사용하여 이벤트에 대한 처리기를 지정할 수 있습니다. 이 옵션은 코드 숨김 파일의 메서드를 사용하여 이벤트를 처리하는 추가 옵션입니다. 클래스에 ListViewDoubleTapped
이벤트 처리기가 있다고 가정 MainWindow
해 보겠습니다.
public sealed partial class MainWindow : Window
{
...
public void ListViewDoubleTapped()
{
// Handle double-tapped logic
}
}
그런 다음 다음과 같이 ListView의 DoubleTapped 이벤트를 MainWindow 의 메서드에 바인딩할 수 있습니다.
<ListView DoubleTapped="{x:Bind ListViewDoubleTapped}" />
오버로드된 메서드는 이 기술을 사용하여 이벤트를 처리하는 데 사용할 수 없습니다. 또한 이벤트를 처리하는 메서드에 매개 변수가 있는 경우 이벤트의 모든 매개 변수 형식에서 각각 할당할 수 있어야 합니다. 이 경우 ListViewDoubleTapped
오버로드되지 않고 매개 변수가 없습니다(하지만 두 개의 object
매개 변수를 사용한 경우에도 여전히 유효합니다).
이벤트 바인딩 기술은 명령을 구현하고 사용하는 것과 유사합니다(명령은 ICommand 인터페이스를 구현하는 개체를 반환하는 속성임).
{x:Bind} 및 {Binding} 모두 명령으로 작동합니다. 명령 패턴을 여러 번 구현할 필요가 없도록 DelegateCommand
UWP 샘플("Common" 폴더)에서 찾을 도우미 클래스를 사용할 수 있습니다.
폴더 또는 파일 컬렉션에 바인딩
Windows.Storage 네임스페이스의 API를 사용하여 패키지된 Windows 앱 SDK 앱에서 폴더 및 파일 데이터를 검색할 수 있습니다. 그러나 다양한 GetFilesAsync
및 GetFoldersAsync
GetItemsAsync
메서드는 컨트롤을 나열하는 바인딩에 적합한 값을 반환하지 않습니다. 대신 FileInformationFactory 클래스의 GetVirtualizedFilesVector, GetVirtualizedFoldersVector 및 GetVirtualizedItemsVector 메서드의 반환 값에 바인딩해야 합니다.
StorageDataSource 및 GetVirtualizedFilesVector UWP 샘플의 다음 코드 예제는 일반적인 사용 패턴을 보여 줍니다. 앱 패키지 매니페스트에서 picturesLibrary 기능을 선언하고 사진 라이브러리 폴더에 그림이 있는지 확인해야 합니다.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var library = Windows.Storage.KnownFolders.PicturesLibrary;
var queryOptions = new Windows.Storage.Search.QueryOptions();
queryOptions.FolderDepth = Windows.Storage.Search.FolderDepth.Deep;
queryOptions.IndexerOption = Windows.Storage.Search.IndexerOption.UseIndexerWhenAvailable;
var fileQuery = library.CreateFileQueryWithOptions(queryOptions);
var fif = new Windows.Storage.BulkAccess.FileInformationFactory(
fileQuery,
Windows.Storage.FileProperties.ThumbnailMode.PicturesView,
190,
Windows.Storage.FileProperties.ThumbnailOptions.UseCurrentScale,
false
);
var dataSource = fif.GetVirtualizedFilesVector();
this.PicturesListView.ItemsSource = dataSource;
}
일반적으로 이 방법을 사용하여 파일 및 폴더 정보의 읽기 전용 보기를 만듭니다. 파일 및 폴더 속성에 대한 양방향 바인딩을 만들 수 있습니다. 예를 들어 사용자가 음악 보기에서 노래를 평가하도록 할 수 있습니다. 그러나 적절한 SavePropertiesAsync
메서드(예: MusicProperties.SavePropertiesAsync)를 호출할 때까지 변경 내용은 유지되지 않습니다. 선택 재설정을 트리거하므로 항목이 포커스를 잃을 때 변경 내용을 커밋해야 합니다.
이 기술을 사용하는 양방향 바인딩은 음악과 같은 인덱싱된 위치에서만 작동합니다. FolderInformation.GetIndexedStateAsync 메서드를 호출하여 위치가 인덱싱되는지 여부를 확인할 수 있습니다.
또한 가상화된 벡터는 값을 채우기 전에 일부 항목에 대해 반환 null
할 수 있습니다. 예를 들어 가상화된 벡터에 null
바인딩된 목록 컨트롤의 SelectedItem 값을 사용하거나 SelectedIndex 를 대신 사용하기 전에 확인해야 합니다.
키로 그룹화된 데이터에 바인딩
항목의 플랫 컬렉션(예: 클래스가 BookSku
나타내는 책)을 사용하고 공통 속성을 키( BookSku.AuthorName
예: 속성)로 사용하여 항목을 그룹화하면 결과를 그룹화된 데이터라고 합니다. 데이터를 그룹화하면 더 이상 플랫 컬렉션이 아닙니다. 그룹화된 데이터는 각 그룹 개체에 다음이 있는 그룹 개체의 컬렉션입니다.
- 키 및
- 속성이 해당 키와 일치하는 항목의 컬렉션입니다.
책 예제를 다시 사용하려면 책 이름을 사용하여 책을 그룹화하면 각 그룹에 다음이 있는 작성자 이름 그룹의 컬렉션이 생성됩니다.
- 작성자 이름인 키 및
- 속성이
BookSku
그룹의 키와 일치하는 개체AuthorName
의 컬렉션입니다.
일반적으로 컬렉션을 표시하려면 항목 컨트롤의 ItemsSource (예: ListView 또는 GridView)를 컬렉션을 반환하는 속성에 직접 바인딩합니다. 항목의 플랫 컬렉션인 경우 특별한 작업을 수행할 필요가 없습니다. 그러나 그룹화된 데이터에 바인딩할 때처럼 그룹 개체의 컬렉션인 경우 항목 컨트롤과 바인딩 원본 사이에 있는 CollectionViewSource 라는 중간 개체의 서비스가 필요합니다. 그룹화된 데이터를 반환하는 속성에 바인딩 CollectionViewSource
하고 항목 컨트롤 CollectionViewSource
을 에 바인딩합니다. 추가 값 추가 CollectionViewSource
는 현재 항목을 추적하므로 둘 이상의 항목 컨트롤을 모두 동일한 CollectionViewSource
항목에 바인딩하여 동기화된 상태로 유지할 수 있다는 것입니다.
CollectionViewSource.View 속성에서 반환된 개체의 ICollectionView.CurrentItem 속성을 통해 프로그래밍 방식으로 현재 항목에 액세스할 수도 있습니다.
CollectionViewSource의 그룹화 기능을 활성화하려면 IsSourceGrouped를 true
.로 설정합니다.
ItemsPath 속성도 설정해야 하는지 여부는 그룹 개체를 작성하는 방법에 따라 달라집니다. 그룹 개체를 작성하는 방법에는 "is-a-group" 패턴과 "has-a-group" 패턴의 두 가지가 있습니다. "is-a-group" 패턴에서 그룹 개체는 컬렉션 형식(예: List<T>
)에서 파생되므로 그룹 개체는 실제로 항목 그룹 자체입니다. 이 패턴을 사용하면 설정할 ItemsPath
필요가 없습니다. "has-a-group" 패턴에서 그룹 개체에는 컬렉션 형식의 하나 이상의 속성(예: List<T>
)이 있으므로 그룹은 속성 형식의 항목 그룹(또는 여러 속성 형식의 여러 항목 그룹)을 "가집니다". 이 패턴을 사용하면 항목 그룹을 포함하는 속성의 이름으로 설정 ItemsPath
해야 합니다.
아래 예제에서는 "has-a-group" 패턴을 보여 줍니다. 창 클래스에는 뷰 모델의 인스턴스를 반환하는 DataContext라는 속성이 있습니다.
CollectionViewSource는 그룹 개체의 컬렉션인 뷰 모델의Authors
속성에 바인딩 Authors
하고 그룹화된 항목을 포함하는 속성임을 지정 Author.BookSkus
합니다. 마지막으로 GridView 는 그룹에 바인딩 CollectionViewSource
되고 그룹의 항목을 렌더링할 수 있도록 그룹 스타일이 정의됩니다.
<Window.Resources>
<CollectionViewSource
x:Name="AuthorHasACollectionOfBookSku"
Source="{x:Bind ViewModel.Authors}"
IsSourceGrouped="true"
ItemsPath="BookSkus"/>
</Window.Resources>
...
<GridView
ItemsSource="{x:Bind AuthorHasACollectionOfBookSku}" ...>
<GridView.GroupStyle>
<GroupStyle
HeaderTemplate="{StaticResource AuthorGroupHeaderTemplateWide}" ... />
</GridView.GroupStyle>
</GridView>
두 가지 방법 중 하나로 "is-a-group" 패턴을 구현할 수 있습니다. 한 가지 방법은 고유한 그룹 클래스를 작성하는 것입니다. 클래스 List<T>
를 파생합니다(여기서 T 는 항목의 형식). 예: public class Author : List<BookSku>
. 두 번째 방법은 LINQ 식을 사용하여 BookSku 항목의 속성 값과 같은 그룹 개체(및 그룹 클래스)를 동적으로 만드는 것입니다. 이 방법은 항목의 플랫 목록만 유지하고 즉석에서 그룹화하여 클라우드 서비스의 데이터에 액세스하는 앱의 일반적입니다. Author 및Genre와 같은 특별한 그룹 클래스 없이도 저자 또는 장르별로 책을 유연하게 그룹화할 수 있습니다.
아래 예제에서는 LINQ를 사용하는 "is-a-group" 패턴을 보여 줍니다. 이번에는 그룹 머리글에 장르 이름으로 표시된 장르별로 책을 그룹화합니다. 이는 그룹 키 값을 참조하는 "Key" 속성 경로로 표시됩니다.
using System.Linq;
...
private IOrderedEnumerable<IGrouping<string, BookSku>> genres;
public IOrderedEnumerable<IGrouping<string, BookSku>> Genres
{
get
{
if (genres == null)
{
genres = from book in bookSkus
group book by book.genre into grp
orderby grp.Key
select grp;
}
return genres;
}
}
데이터 템플릿과 함께 {x:Bind} 를 사용할 때는 값을 설정 x:DataType
하여 바인딩되는 형식을 나타내야 합니다. 형식이 제네릭인 경우 태그에서 이를 표현할 수 없으므로 그룹 스타일 헤더 템플릿 대신 {Binding} 을(를) 사용해야 합니다.
<Grid.Resources>
<CollectionViewSource x:Name="GenreIsACollectionOfBookSku"
Source="{x:Bind Genres}"
IsSourceGrouped="true"/>
</Grid.Resources>
<GridView ItemsSource="{x:Bind GenreIsACollectionOfBookSku}">
<GridView.ItemTemplate x:DataType="local:BookTemplate">
<DataTemplate>
<TextBlock Text="{x:Bind Title}"/>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Key}"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
SemanticZoom 컨트롤은 사용자가 그룹화된 데이터를 보고 탐색할 수 있는 좋은 방법입니다.
Bookstore2 UWP 샘플 앱은 SemanticZoom
. 해당 앱에서 저자(축소 보기)로 그룹화된 책 목록을 보거나 축소하여 저자의 점프 목록(축소 보기)을 볼 수 있습니다. 점프 목록은 책 목록을 스크롤하는 것보다 훨씬 빠른 탐색을 제공합니다. 확대 및 축소 보기는 실제로 ListView
또는 GridView
컨트롤이 동일한 CollectionViewSource
컨트롤에 바인딩됩니다.
범주 내의 하위 범주와 같은 계층적 데이터에 바인딩하는 경우 일련의 항목 컨트롤을 사용하여 UI의 계층 수준을 표시하도록 선택할 수 있습니다. 한 항목 컨트롤의 선택 영역에 따라 후속 항목 컨트롤의 내용이 결정됩니다. 각 목록을 자체 CollectionViewSource 에 바인딩하고 인스턴스를 체인에 함께 바인딩 CollectionViewSource
하여 목록을 동기화된 상태로 유지할 수 있습니다. 이를 마스터/세부 정보(또는 목록/세부 정보) 보기라고 합니다. 자세한 내용은 계층적 데이터에 바인딩하고 마스터/세부 정보 보기를 만드는 방법을 참조하세요.
데이터 바인딩 문제 진단 및 디버깅
바인딩 태그에는 속성의 이름이 포함되며 C#의 경우 필드와 메서드도 포함됩니다. 따라서 속성의 이름을 바꿀 때 속성을 참조하는 바인딩도 변경해야 합니다. 이를 잊어버리면 데이터 바인딩 버그의 일반적인 예가 발생하며 앱이 컴파일되지 않거나 올바르게 실행되지 않습니다.
{x:Bind} 및 {Binding}에서 만든 바인딩 개체는 대체로 기능적으로 동일합니다. 그러나 {x:Bind}
바인딩 소스에 대한 형식 정보가 있으며 컴파일 시간에 소스 코드를 생성합니다. 그러면 {x:Bind}
코드의 나머지 부분과 동일한 종류의 문제 검색을 얻을 수 있습니다. 여기에는 바인딩 식의 컴파일 시간 유효성 검사와 페이지의 partial 클래스로 생성된 소스 코드에서 중단점을 설정하여 디버깅하는 것이 포함됩니다. 이러한 클래스는 폴더의 파일( obj
예: C#) <view name>.g.cs
과 같은 이름으로 찾을 수 있습니다. 바인딩에 문제가 있는 경우 Microsoft Visual Studio 디버거에서 처리되지 않은 예외 중단을 켭니다. 디버거는 해당 시점에서 실행을 중단한 다음 무엇이 잘못되었는지 디버그할 수 있습니다. 생성된 {x:Bind}
코드는 바인딩 소스 노드 그래프의 각 부분에 대해 동일한 패턴을 따르며, 호출 스택 창의 정보를 사용하여 문제를 발생시킨 호출 시퀀스를 확인할 수 있습니다.
{Binding} 에 바인딩 원본에 대한 형식 정보가 없습니다. 그러나 디버거가 연결된 상태로 앱을 실행하면 Visual Studio의 출력 및 XAML 바인딩 실패 창에 바인딩 오류가 표시됩니다. Visual Studio에서 바인딩 오류를 디버깅하는 방법에 대한 자세한 내용은 XAML 데이터 바인딩 진단을 참조하세요.
코드에서 바인딩 만들기
비고
이 섹션은 코드에서 {x:Bind} 바인딩을 만들 수 없으므로 {Binding}에만 적용됩니다. 그러나 {x:Bind}
을 사용하면 종속성 속성에 대한 변경 알림을 등록할 수 있는 동일한 이점을 얻을 수 있습니다.
XAML 대신 절차 코드를 사용하여 데이터에 UI 요소를 연결할 수도 있습니다. 이렇게 하려면 새 Binding 개체를 만들고 적절한 속성을 설정한 다음 FrameworkElement.SetBinding 또는 BindingOperations.SetBinding을 호출합니다. 프로그래밍 방식으로 바인딩을 만드는 것은 런타임에 바인딩 속성 값을 선택하거나 여러 컨트롤 간에 단일 바인딩을 공유하려는 경우에 유용합니다. 그러나 호출 SetBinding
한 후에는 바인딩 속성 값을 변경할 수 없습니다.
다음 예제에서는 코드에서 바인딩을 구현하는 방법을 보여줍니다.
<TextBox x:Name="MyTextBox" Text="Text"/>
// Create an instance of the MyColors class
// that implements INotifyPropertyChanged.
var textcolor = new MyColors();
// Brush1 is set to be a SolidColorBrush with the value Red.
textcolor.Brush1 = new SolidColorBrush(Colors.Red);
// Set the DataContext of the TextBox MyTextBox.
MyTextBox.DataContext = textcolor;
// Create the binding and associate it with the text box.
var binding = new Binding { Path = new PropertyPath("Brush1") };
MyTextBox.SetBinding(TextBox.ForegroundProperty, binding);
{x:Bind} 및 {Binding} 기능 비교
특징 | {x:Bind} vs. {Binding} | 비고 |
---|---|---|
경로가 기본 속성입니다. | {x:Bind a.b.c} - {Binding a.b.c} |
|
Path 속성 | {x:Bind Path=a.b.c} - {Binding Path=a.b.c} |
x:Bind 에서 Path 기본적으로 DataContext가 아닌 창에 루팅됩니다. |
인덱서 | {x:Bind Groups[2].Title} - {Binding Groups[2].Title} |
컬렉션에서 지정된 항목에 바인딩합니다. 정수 기반 인덱스만 지원됩니다. |
연결된 속성 | {x:Bind Button22.(Grid.Row)} - {Binding Button22.(Grid.Row)} |
연결된 속성은 괄호를 사용하여 지정됩니다. 속성이 XAML 네임스페이스에 선언되지 않은 경우 문서의 머리글에 있는 코드 네임스페이스에 매핑되어야 하는 xml 네임스페이스로 접두사를 지정합니다. |
주조 | {x:Bind groups[0].(data:SampleDataGroup.Title)} - 에 필요하지 {Binding} 않습니다. |
캐스트는 괄호를 사용하여 지정됩니다. 속성이 XAML 네임스페이스에 선언되지 않은 경우 문서의 머리글에 있는 코드 네임스페이스에 매핑되어야 하는 xml 네임스페이스로 접두사를 지정합니다. |
변환기 | {x:Bind IsShown, Converter={StaticResource BoolToVisibility}} - {Binding IsShown, Converter={StaticResource BoolToVisibility}} |
변환기는 Window/Control/ResourceDictionary의 루트 또는 App.xaml에서 선언해야 합니다. |
ConverterParameter, ConverterLanguage | {x:Bind IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr} - {Binding IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr} |
변환기는 Window/Control/ResourceDictionary의 루트 또는 App.xaml에서 선언해야 합니다. |
TargetNullValue | {x:Bind Name, TargetNullValue=0} - {Binding Name, TargetNullValue=0} |
바인딩 식의 리프가 null일 때 사용됩니다. 문자열 값에 작은따옴표를 사용합니다. |
FallbackValue | {x:Bind Name, FallbackValue='empty'} - {Binding Name, FallbackValue='empty'} |
바인딩 경로의 일부(리프 제외)가 null일 때 사용됩니다. |
ElementName | {x:Bind slider1.Value} - {Binding Value, ElementName=slider1} |
{x:Bind} 필드에 Path 바인딩하는 경우 기본적으로 Window에 루팅되므로 명명된 모든 요소는 해당 필드를 통해 액세스할 수 있습니다. |
RelativeSource: Self | <Rectangle x:Name="rect1" Width="200" Height="{x:Bind rect1.Width}" ... /> - <Rectangle Width="200" Height="{Binding Width, RelativeSource={RelativeSource Self}}" ... /> |
를 사용하여 {x:Bind} 요소의 이름을 지정하고 해당 이름을 Path 사용합니다. |
RelativeSource: TemplatedParent | 에 필요하지 않음 {x:Bind} - {Binding <path>, RelativeSource={RelativeSource TemplatedParent}} |
With {x:Bind} , TargetType on ControlTemplate 은 템플릿 부모에 대한 바인딩을 나타냅니다. 대부분의 경우 {Binding} 컨트롤 템플릿에서 일반 템플릿 바인딩을 사용할 수 있습니다. 그러나 변환기 또는 양방향 바인딩을 사용해야 하는 위치에 사용합니다 TemplatedParent . |
출처 | 에 필요하지 않음 {x:Bind} - <ListView ItemsSource="{Binding Orders, Source={StaticResource MyData}}"/> |
{x:Bind} 명명된 요소를 직접 사용할 수 있으므로 속성 또는 정적 경로를 사용합니다. |
Mode | {x:Bind Name, Mode=OneWay} - {Binding Name, Mode=TwoWay} |
Mode 가 될 수 있습니다OneTime .OneWay TwoWay |
UpdateSourceTrigger | {x:Bind Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged} - {Binding UpdateSourceTrigger=PropertyChanged} |
UpdateSourceTrigger 가 될 수 있습니다Default .LostFocus PropertyChanged
{x:Bind} 은 (을) 지원하지 UpdateSourceTrigger=Explicit 않습니다.
{x:Bind} 는 PropertyChanged 동작을 사용하는 경우를 제외한 TextBox.Text 모든 경우에 대해 동작을 사용합니다 LostFocus . |
참고하십시오
Windows developer