Xamarin.Forms 컴파일된 바인딩

Download Sample 샘플 다운로드

컴파일된 바인딩을 클래식 바인딩보다 더 빨리 확인할 수 있으므로 Xamarin.Forms 애플리케이션에서 데이터 바인딩 성능이 향상됩니다.

데이터 바인딩에는 두 개의 주요 문제가 있습니다.

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

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

컴파일된 바인딩을 사용하는 프로세스는 다음과 같습니다.

  1. XAML 컴파일 사용 XAML 컴파일에 대한 자세한 내용은 XAML 컴파일을 참조하세요.
  2. VisualElementx:DataType 특성을 VisualElement 및 자식이 바인딩되는 개체의 형식으로 설정합니다.

참고 항목

BindingContext로 설정되므로 뷰 계층 구조의 동일한 수준으로 x:DataType 특성을 설정하는 것이 좋습니다. 그러나 이 특성은 뷰 계층 구조의 모든 위치에서 다시 정의할 수 있습니다.

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

Important

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

컴파일된 바인딩 사용

컴파일된 색상 선택기 페이지에서는 Xamarin.Forms 뷰 및 viewmodel 속성 간에 컴파일된 바인딩을 사용하는 방법을 보여 줍니다.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.CompiledColorSelectorPage"
             Title="Compiled Color Selector">
    ...
    <StackLayout x:DataType="local:HslColorViewModel">
        <StackLayout.BindingContext>
            <local:HslColorViewModel Color="Sienna" />
        </StackLayout.BindingContext>
        <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>

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

Important

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

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

애플리케이션을 처음 실행하는 경우 BoxView, Label 요소 및 Slider 요소는 viewmodel을 인스턴스화했을 때 설정된 초기 Color 속성에 따라 모두 viewmodel에서 설정됩니다. 이 과정은 다음 스크린샷에 나와 있습니다.

Compiled Color Selector

슬라이더를 조작하는 대로 적절히 BoxViewLabel 요소를 업데이트합니다.

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

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

DataTemplate의 바인딩은 템플릿이 적용된 개체의 컨텍스트로 해석됩니다. 따라서 DataTemplate에서 컴파일된 바인딩을 사용하는 경우 DataTemplatex:DataType 특성을 사용하여 해당 데이터 개체의 형식을 선언해야 합니다.

컴파일된 색상 목록 페이지에서는 DataTemplate에서 컴파일된 바인딩을 사용하는 방법을 보여줍니다.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.CompiledColorListPage"
             Title="Compiled Color List">
    <Grid>
        ...
        <ListView x:Name="colorListView"
                  ItemsSource="{x:Static local:NamedColor.All}"
                  ... >
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="local:NamedColor">
                    <ViewCell>
                        <StackLayout Orientation="Horizontal">
                            <BoxView Color="{Binding Color}"
                                     ... />
                            <Label Text="{Binding FriendlyName}"
                                   ... />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <!-- The BoxView doesn't use compiled bindings -->
        <BoxView Color="{Binding Source={x:Reference colorListView}, Path=SelectedItem.Color}"
                 ... />
    </Grid>
</ContentPage>

ListView.ItemsSource 속성은 NamedColor.All 정적 속성으로 설정됩니다. NamedColor 클래스는 .NET 리플렉션을 사용하여 Color 구조에서 모든 정적 공용 필드를 열거하고 All 정적 속성에서 액세스할 수 있는 컬렉션의 이름으로 저장합니다. 따라서 ListView는 모든 NamedColor 인스턴스로 채워집니다. ListView의 각 항목의 경우 해당 항목에 대한 바인딩 컨텍스트는 NamedColor 개체로 설정됩니다. ViewCellBoxViewLabel 요소는 NamedColor 속성에 바인딩됩니다.

DataTemplatex:DataType 특성을 NamedColor 형식으로 정의하고 DataTemplate 뷰 계층 구조의 모든 바인딩 식을 컴파일한다는 것을 나타냅니다. 결국 빌드 오류로 나타나는 존재하지 않는 NamedColor 속성에 바인딩하려면 바인딩 식 중 하나를 변경하여 확인할 수 있습니다. 이 예제에서는 x:DataType 특성을 문자열 리터럴로 설정하고 있지만, x:Type 태그 확장을 사용하여 형식으로 설정할 수도 있습니다. x:Type 태그 확장에 대한 자세한 내용은 x:Type 태그 확장을 참조하세요.

애플리케이션을 처음 실행하는 경우 ListViewNamedColor 인스턴스로 채워집니다. ListView의 항목을 선택하면 BoxView.Color 속성이 ListView에서 선택한 항목의 색상으로 설정됩니다.

Compiled Color List

ListView에서 다른 항목을 선택하면 BoxView의 색상을 업데이트합니다.

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

바인딩 식은 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을 참조하세요.

성능

컴파일된 바인딩은 다양한 성능 이점으로 데이터 바인딩 성능을 향상시킵니다. 단위 테스트는 다음을 보여줍니다.

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

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