다음을 통해 공유


컴파일된 바인딩

샘플을 찾아봅니다. 샘플 찾아보기

.NET 다중 플랫폼 앱 UI(.NET MAUI) 데이터 바인딩에는 다음과 같은 두 가지 주요 문제가 있습니다.

  1. 바인딩 식의 컴파일 시간 유효성 검사가 없습니다. 대신 바인딩을 런타임 시 확인합니다. 따라서 애플리케이션이 예상대로 동작하지 않거나 오류 메시지가 나타나는 경우 모든 잘못된 바인딩은 런타임 때까지 검색되지 않습니다.
  2. 데이터 바인딩은 비용 효율적이지 않습니다. 범용 개체 검사(리플렉션)를 사용하여 런타임 시 바인딩을 확인하므로 이 작업을 수행하는 오버헤드는 플랫폼마다 다릅니다.

컴파일된 바인딩은 런타임이 아닌 컴파일 시간에 바인딩 식을 확인하여 .NET MAUI 애플리케이션에서 데이터 바인딩 성능을 향상시킵니다. 또한 이 바인딩 식의 컴파일 시간 유효성 검사를 사용하면 잘못된 바인딩이 빌드 오류로 보고되기 때문에 개발자의 문제 해결 환경을 개선할 수 있습니다.

Important

컴파일된 바인딩은 NativeAOT 앱의 문자열 기반 바인딩 대신, 전체 트리밍이 사용하도록 설정된 앱에서 필요합니다. 자세한 내용은 .NET MAUI 앱네이티브 AOT 배포 트리밍을 참조하세요.

XAML의 컴파일된 바인딩

XAML에서 컴파일된 바인딩을 사용하려면 해당 자식 VisualElement 이 바인딩할 개체 VisualElement 의 형식으로 특성을 설정합니다x:DataType. BindingContext로 설정되므로 뷰 계층 구조의 동일한 수준으로 x:DataType 특성을 설정하는 것이 좋습니다. 그러나 이 특성은 뷰 계층 구조의 모든 위치에서 다시 정의할 수 있습니다.

Important

컴파일된 바인딩은 .NET MAUI에서 기본적으로 사용하도록 설정된 XAML 컴파일을 사용해야 합니다. XAML 컴파일을 사용하지 않도록 설정한 경우 XAML 컴파일을 사용하도록 설정해야 합니다. 자세한 내용은 XAML 컴파일을 참조하세요.

XAML에서 컴파일된 바인딩을 사용하려면 특성이 x:DataType 문자열 리터럴 또는 태그 확장을 사용하는 x:Type 형식으로 설정되어야 합니다. XAML 컴파일 시간에 잘못된 바인딩 식은 빌드 오류로 보고됩니다. 그러나 XAML 컴파일러는 발견되는 첫 번째 잘못된 바인딩 식에 대한 빌드 오류만 보고합니다. VisualElement 또는 자식에서 정의된 모든 유효한 바인딩 식은 BindingContext가 XAML 또는 코드로 설정됐는지 여부에 관계 없이 컴파일됩니다. 바인딩 식을 컴파일하면 원본의 속성에서 값을 가져오고 태그에서 지정되는 대상의 속성에서 그 값을 설정하는 컴파일된 코드를 생성합니다. 또한 바인딩 식에 따라 생성된 코드는 원본 속성의 값의 변경 내용을 관찰하고 대상 속성을 새로 고침하여 거꾸로 대상부터 원본까지 변경 내용을 푸시할 수 있습니다.

Important

컴파일된 바인딩은 속성을 정의하는 모든 XAML 바인딩 식에 Source 대해 사용하지 않도록 설정됩니다. 이는 컴파일 시간에 확인할 수 없는 x:Reference 태그 확장을 사용하여 항상 Source 속성이 설정되기 때문입니다.

또한 XAML의 컴파일된 바인딩은 현재 다중 바인딩에서 지원되지 않습니다.

기본적으로 .NET MAUI는 컴파일된 바인딩을 사용하지 않는 XAML 바인딩에 대한 빌드 경고를 생성하지 않습니다. 그러나 빌드 속성을 앱의 프로젝트 파일(*.csproj)로 설정 $(MauiStrictXamlCompilation) 하여 생성되는 컴파일된 바인딩 경고를 옵트인할 true 수 있습니다.

<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>

기본적으로 .NET MAUI는 컴파일된 바인딩을 사용하지 않는 XAML 바인딩에 대한 빌드 경고를 생성합니다.

XAML 컴파일된 바인딩 경고에 대한 자세한 내용은 XAML 컴파일 바인딩 경고를 참조 하세요.

XAML에서 컴파일된 바인딩 사용

다음 예제에서는 .NET MAUI 뷰와 viewmodel 속성 간에 컴파일된 바인딩을 사용하는 방법을 보여 줍니다.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.CompiledColorSelectorPage"
             x:DataType="local:HslColorViewModel"
             Title="Compiled Color Selector">
    <ContentPage.BindingContext>
        <local:HslColorViewModel Color="Sienna" />
    </ContentPage.BindingContext>
    ...
    <StackLayout>
        <BoxView Color="{Binding Color}"
                 ... />
        <StackLayout Margin="10, 0">
            <Label Text="{Binding Name}" />
            <Slider Value="{Binding Hue}" />
            <Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
            <Slider Value="{Binding Saturation}" />
            <Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
            <Slider Value="{Binding Luminosity}" />
            <Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
        </StackLayout>
    </StackLayout>    
</ContentPage>

속성 ContentPageHslColorViewModel 대한 BindingContext 속성 요소 태그 내에서 속성을 인스턴스화하고 초기화 Color 합니다. ContentPage 또한 뷰 계층의 바인딩 식 ContentPage 이 컴파일됨을 나타내는 viewmodel 형식으로 특성을 정의 x:DataType 합니다. 결국 빌드 오류로 나타나는 존재하지 않는 viewmodel 속성에 바인딩하려면 바인딩 식 중 하나를 변경하여 확인할 수 있습니다. 이 예제에서는 x:DataType 특성을 문자열 리터럴로 설정하고 있지만, x:Type 태그 확장을 사용하여 형식으로 설정할 수도 있습니다. x:Type 태그 확장에 대한 자세한 내용은 x:Type 태그 확장을 참조하세요.

Important

x:DataType 특성은 뷰 계층 구조의 모든 지점에서 다시 정의할 수 있습니다.

BoxView, Label 요소 및 Slider 뷰는 ContentPage에서 바인딩 컨텍스트를 상속받습니다. 이러한 뷰는 모두 viewmodel의 원본 속성을 참조하는 바인딩 대상입니다. BoxView.Color 속성 및 Label.Text 속성의 경우 데이터 바인딩은 OneWay이며, 뷰의 속성은 viewmodel의 속성에서 설정됩니다. 그러나 Slider.Value 속성은 TwoWay 바인딩을 사용합니다. 이렇게 하면 각 Slider를 viewmodel에서 설정하고 각 Slider에서 viewmodel을 설정할 수 있습니다.

예제를 처음 실행 BoxViewLabel 하면 viewmodel이 인스턴스화되었을 때 초기 Color 속성 집합에 따라 viewmodel에서 , 요소 및 Slider 요소가 모두 설정됩니다. 슬라이더가 조작 BoxView 되면 그에 따라 요소 및 Label 요소가 업데이트됩니다.

컴파일된 색 선택기입니다.

이 색 선택기에 대한 자세한 내용은 ViewModels 및 속성 변경 알림을 참조 하세요.

DataTemplate의 XAML에서 컴파일된 바인딩 사용

DataTemplate의 바인딩은 템플릿이 적용된 개체의 컨텍스트로 해석됩니다. 따라서 DataTemplate에서 컴파일된 바인딩을 사용하는 경우 DataTemplatex:DataType 특성을 사용하여 해당 데이터 개체의 형식을 선언해야 합니다. 이렇게 하지 않으면 부모 범위에서 잘못된 x:DataType 상속이 발생할 DataTemplate 수 있습니다.

<ContentPage ...
             x:DataType="local:AnimalsPageViewModel">
    <!-- Binding to AnimalsPageViewModel.Animals -->
    <CollectionView ItemsSource="{Binding Animals}">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <!-- incorrect: compiler thinks you want to bind to AnimalsPageViewModel.Name -->  
                <Label Text="{Binding Name}" />
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

다음 예제에서는 다음을 올바르게 설정하는 방법을 x:DataType 보여 줍니다.DataTemplate

<ContentPage ...
             x:DataType="local:AnimalsPageViewModel">
    <!-- Binding to AnimalsPageViewModel.Animals -->
    <CollectionView ItemsSource="{Binding Animals}">
        <CollectionView.ItemTemplate>
            <DataTemplate x:DataType="local:Animal">
                <!-- correct: compiler knows you want to bind to Animal.Name -->
                <Label Text="{Binding Name}" />
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

이 예제에서는 x:DataType 특성을 문자열 리터럴로 설정하고 있지만, x:Type 태그 확장을 사용하여 형식으로 설정할 수도 있습니다. x:Type 태그 확장에 대한 자세한 내용은 x:Type 태그 확장을 참조하세요.

속성을 정의하는 Source 바인딩 컴파일

.NET MAUI 9 이전에는 XAML 컴파일러가 속성 대신 속성을 정의하는 Source 바인딩 컴파일을 BindingContext건너뜁니다. .NET MAUI 9에서 이러한 바인딩을 컴파일하여 더 나은 런타임 성능을 활용할 수 있습니다. 그러나 이 최적화는 기존 앱 코드의 호환성이 손상되지 않도록 기본적으로 사용하도록 설정되지 않습니다. 이 최적화를 사용하도록 설정하려면 빌드 속성을 true 앱의 프로젝트 파일로 설정합니다$(MauiEnableXamlCBindingWithSourceCompilation).

<MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation>

그런 다음 모든 바인딩에 올바른 x:DataType 주석이 추가되고 부모 범위에서 잘못된 데이터 형식을 상속하지 않는지 확인합니다.

<HorizontalStackLayout BindingContext="{x:Reference slider}" x:DataType="Slider">
    <Label Text="{Binding Value}" />
    <Label Text="{Binding Text, Source={x:Reference entry}, x:DataType=Entry}" />
</HorizontalStackLayout>

참고 항목

바인딩Source이 있지만 부모로부터 상속 x:DataType 되는 경우 형식과 형식Sourcex:DataType 일치하지 않을 수 있습니다. 이 시나리오에서는 경고가 생성되고 런타임 시 바인딩 경로를 확인하는 리플렉션 기반 바인딩으로 대체됩니다.

XAML에서 컴파일된 바인딩과 클래식 바인딩 결합

바인딩 식은 x:DataType 특성을 정의하는 뷰 계층 구조에 대해서만 컴파일됩니다. 반대로 x:DataType 특성을 정의하지 않는 계층 구조의 모든 뷰는 클래식 바인딩을 사용합니다. 따라서 페이지에서 컴파일된 바인딩 및 클래식 바인딩을 결합할 수 있습니다. 예를 들어 이전 섹션에서 DataTemplate 내의 뷰는 컴파일된 바인딩을 사용하는 반면 ListView에서 선택된 색상으로 설정된 BoxView은 사용하지 않습니다.

따라서 x:DataType 특성을 신중하게 구성하면 컴파일된 바인딩 및 클래식 바인딩을 사용하는 페이지가 표시될 수 있습니다. 또는 x:DataType 특성은 언제든지 뷰 계층 구조에서 x:Null 태그 확장을 사용하는 null로 다시 정의될 수 있습니다. 이 작업을 수행하면 뷰 계층 구조 내의 모든 바인딩 식이 클래식 바인딩을 사용한다는 것이 표시됩니다. 다음 예제에서는 이 방법을 보여 줍니다.

<StackLayout x:DataType="local:HslColorViewModel">
    <StackLayout.BindingContext>
        <local:HslColorViewModel Color="Sienna" />
    </StackLayout.BindingContext>
    <BoxView Color="{Binding Color}"
             VerticalOptions="FillAndExpand" />
    <StackLayout x:DataType="{x:Null}"
                 Margin="10, 0">
        <Label Text="{Binding Name}" />
        <Slider Value="{Binding Hue}" />
        <Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
        <Slider Value="{Binding Saturation}" />
        <Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
        <Slider Value="{Binding Luminosity}" />
        <Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
    </StackLayout>
</StackLayout>   

루트 StackLayoutx:DataType 특성을 HslColorViewModel 형식으로 설정하고 루트 StackLayout 뷰 계층 구조의 모든 바인딩 식을 컴파일한다는 것을 나타냅니다. 그러나 내부 StackLayoutx:Null 태그 식을 사용하여 x:DataType 특성을 null로 다시 정의합니다. 따라서 내부 StackLayout 내의 바인딩 식은 클래식 바인딩을 사용합니다. 루트 StackLayout 계층 구조 내의 BoxView만 컴파일된 바인딩을 사용합니다.

x:Null 태그 식에 대한 자세한 내용은 x:Null Markup Extension을 참조하세요.

XAML 컴파일된 바인딩 경고

다음 표에서는 컴파일된 바인딩에 대한 컴파일러 경고와 이를 해결하는 방법을 나열합니다.

코드 메시지 해결
XC0022 지정된 경우 x:DataType 런타임 성능을 향상시키기 위해 바인딩을 컴파일할 수 있습니다. XAML에 추가하여 x:DataType 현재 BindingContext형식을 지정합니다. 바인딩 컨텍스트가 변경되는 모든 요소에 추가하는 x:DataType 것이 가장 좋습니다.
XC0023 명시적으로 컴파일되지 않은 경우 x:DataType 런타임 성능을 향상시키기 위해 바인딩을 컴파일할 수 있습니다 null. 올바른 형식으로 바꿉다 x:DataType="{x:Null}" .
코드 메시지
XC0022 지정된 경우 x:DataType 런타임 성능을 향상시키기 위해 바인딩을 컴파일할 수 있습니다.

이 경고를 해결하려면 XAML에 추가하여 x:DataType 현재 BindingContext형식을 지정합니다. 바인딩 컨텍스트가 변경되는 모든 요소에 추가하는 x:DataType 것이 가장 좋습니다.
XC0023 명시적으로 컴파일되지 않은 경우 x:DataType 런타임 성능을 향상시키기 위해 바인딩을 컴파일할 수 있습니다 null.

이 경고를 해결하려면 올바른 형식으로 바꿉 x:DataType="{x:Null}" 다.
XC0024 주석이 외부 범위에서 제공되므로 바인딩이 x:DataType 잘못 컴파일될 수 있습니다. 모든 DataTemplate XAML 요소에 올바른 주석을 추가해야 합니다 x:DataType.

이 경고를 해결하려면 모든 DataTemplate 요소에 올바른 x:DataType주석이 추가되었는지 확인합니다.
XC0025 바인딩은 명시적으로 설정된 Source 속성이 있고 바인딩 Source 의 컴파일을 사용할 수 없으므로 컴파일되지 않았습니다. 프로젝트 파일에서 설정하여 이 최적화를 <MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation> 사용하도록 설정하고 이 바인딩에 대해 올바른 x:DataType 항목이 지정되었는지 확인합니다.

이 경고를 해결하려면 프로젝트 파일에서 빌드 속성을 사용하도록 설정하고 $(MauiEnableXamlCBindingWithSourceCompilation) 모든 바인딩에 적절한 x:DataType주석을 추가합니다.

이러한 경고가 무시되지 않도록 하려면 빌드 속성을 사용하여 오류를 $(WarningsAsErrors) 빌드하도록 특정 경고를 변경하는 것이 좋습니다.

<WarningsAsErrors>$(WarningsAsErrors);XC0022;XC0023</WarningsAsErrors>

이러한 경고를 무시하려면 특정 경고 코드와 $(NoWarn) 함께 빌드 속성을 사용합니다.

<NoWarn>$(NoWarn);XC0022;XC0023</NoWarn>

Important

XC0022빌드 XC0023 속성이 .로 설정true되지 않으면 $(MauiStrictXamlCompilation) 경고가 항상 표시되지 않습니다.

앱의 프로젝트 파일에서 빌드 속성을 true 설정 $(TreatWarningsAsErrors) 하지만 특정 XAML 컴파일러 경고를 무시하려는 경우 빌드 속성을 사용하여 이러한 경고를 묵인하거나 $(WarningsNotAsErrors) 빌드 속성을 사용하여 $(NoWarn) 특정 코드의 심각도를 줄입니다.

기본적으로 .NET MAUI는 컴파일된 바인딩을 사용하지 않는 XAML 바인딩에 대한 빌드 경고를 생성합니다. 앱의 프로젝트 파일(*.csproj)에서 속성을 설정하고 $(MauiStrictXamlCompilation) $(TreatWarningsAsErrors) 빌드하여 오류로 처리되는 컴파일된 바인딩 경고를 옵트인할 true 수 있습니다.

<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>

참고 항목

기본적으로 $(MauiStrictXamlCompilation) 빌드 속성은 false 전체 트리밍 또는 NativeAOT를 사용하여 앱을 게시하지 않는 한입니다.

코드의 컴파일된 바인딩

코드로 작성된 바인딩은 일반적으로 리플렉션을 사용하여 런타임에 확인되는 문자열 경로를 사용합니다. 그러나 SetBinding 확장 메서드에는 문자열 경로 대신 인수를 사용하여 바인딩을 Func 정의하는 오버로드도 있습니다.

MyLabel.SetBinding(Label.TextProperty, static (Entry entry) => entry.Text);

컴파일된 바인딩을 정의하는 데 모든 메서드를 사용할 수 있는 것은 아닙니다. 식은 단순 속성 액세스 식이어야 합니다. 다음 예제에서는 유효하고 잘못된 바인딩 식을 보여 줍니다.

// Valid: Property access
static (PersonViewModel vm) => vm.Name;
static (PersonViewModel vm) => vm.Address?.Street;

// Valid: Array and indexer access
static (PersonViewModel vm) => vm.PhoneNumbers[0];
static (PersonViewModel vm) => vm.Config["Font"];

// Valid: Casts
static (Label label) => (label.BindingContext as PersonViewModel).Name;
static (Label label) => ((PersonViewModel)label.BindingContext).Name;

// Invalid: Method calls
static (PersonViewModel vm) => vm.GetAddress();
static (PersonViewModel vm) => vm.Address?.ToString();

// Invalid: Complex expressions
static (PersonViewModel vm) => vm.Address?.Street + " " + vm.Address?.City;
static (PersonViewModel vm) => $"Name: {vm.Name}";

또한 메서드는 BindingBase.Create 바인딩을 사용하여 Func개체에 직접 설정하고 바인딩 개체 인스턴스를 반환합니다.

myEntry.SetBinding(Entry.TextProperty, new MultiBinding
{
    Bindings = new Collection<BindingBase>
    {
        Binding.Create(static (Entry entry) => entry.FontFamily, source: RelativeBindingSource.Self),
        Binding.Create(static (Entry entry) => entry.FontSize, source: RelativeBindingSource.Self),
        Binding.Create(static (Entry entry) => entry.FontAttributes, source: RelativeBindingSource.Self),
    },
    Converter = new StringConcatenationConverter()
});

이러한 컴파일된 바인딩 접근 방식은 다음과 같은 이점을 제공합니다.

  • 런타임이 아닌 컴파일 시간에 바인딩 식을 확인하여 데이터 바인딩 성능을 향상시켰습니다.
  • 잘못된 바인딩이 빌드 오류로 보고되므로 개발자 문제 해결 환경이 향상됩니다.
  • 편집하는 동안 Intellisense.

성능

컴파일된 바인딩은 성능 이점이 다양하여 데이터 바인딩 성능을 향상시킵니다.

  • 속성 변경 알림을 사용하는 컴파일된 바인딩(예: OneWay, OneWayToSource 또는 TwoWay 바인딩)은 클래식 바인딩보다 약 8배 빠르게 확인합니다.
  • 속성 변경 알림을 사용하지 않는 컴파일된 바인딩(예: OneTime 바인딩)은 클래식 바인딩보다 약 20배 빠르게 확인합니다.
  • 속성 변경 알림을 사용하는 컴파일된 바인딩(예: OneWay, OneWayToSource 또는 TwoWay 바인딩)에서 BindingContext를 설정하면 클래식 바인딩에서 BindingContext를 설정하는 것보다 약 5배 빠릅니다.
  • 속성 변경 알림을 사용하지 않는 컴파일된 바인딩(예: OneTime 바인딩)에서 BindingContext를 설정하면 클래식 바인딩에서 BindingContext를 설정하는 것보다 약 7배 빠릅니다.

이러한 성능 차이는 모바일 디바이스에서 수정되며, 사용되는 플랫폼, 사용되는 운영 체제 버전 및 애플리케이션이 실행되는 디바이스에 따라 달라질 수 있습니다.