3부.Part 3. XAML 태그 확장XAML Markup Extensions

샘플 다운로드 샘플 다운로드Download Sample Download the sample

XAML 태그 확장 속성은 다른 소스에서 간접적으로 참조되는 개체 또는 값으로 속성을 설정할 수 있는 XAML에서 중요한 기능을 구성합니다. XAML 태그 확장은 개체를 공유하고 응용 프로그램 전체에서 사용되는 상수를 참조할 때 특히 중요하지만 가장 큰 장점은 데이터 바인딩에서 찾을 수 있습니다.XAML markup extensions constitute an important feature in XAML that allow properties to be set to objects or values that are referenced indirectly from other sources. XAML markup extensions are particularly important for sharing objects, and referencing constants used throughout an application, but they find their greatest utility in data bindings.

XAML 태그 확장XAML Markup Extensions

일반적으로 XAML을 사용하여 문자열, 숫자, 열거형 멤버, 또는 배후에서 값으로 변환되는 문자열 등의 명시적 값으로 개체의 속성을 설정하기 위해 사용합니다.In general, you use XAML to set properties of an object to explicit values, such as a string, a number, an enumeration member, or a string that is converted to a value behind the scenes.

그러나 때로는 속성이 다른 곳에 정의된 값을 대신 참조하거나 런타임 시 코드에 의해 약간의 처리가 필요할 수 있습니다.Sometimes, however, properties must instead reference values defined somewhere else, or which might require a little processing by code at runtime. 이러한 목적에 XAML 태그 확장을 사용할 수 있습니다.For these purposes, XAML markup extensions are available.

해당 XAML 태그 확장은 XML의 확장이 아닙니다.These XAML markup extensions are not extensions of XML. XAML은 완전히 올바른 XML입니다.XAML is entirely legal XML. IMarkupExtension을 구현하는 클래스의 코드에 의해 뒷받침되기 때문에 "extensions"이라 합니다.They’re called “extensions” because they are backed by code in classes that implement IMarkupExtension. 자신의 사용자 지정 태그 확장을 작성할 수 있습니다.You can write your own custom markup extensions.

대부분의 경우에서 XAML 태그 확장은 XAML 파일에서 즉시 인식할 수 있는 중괄호로 구분된 특성 설정 { and }로 표시되지만, 때로는 태그 확장이 전통적인 요소로 태그에 표시됩니다.In many cases, XAML markup extensions are instantly recognizable in XAML files because they appear as attribute settings delimited by curly braces: { and }, but sometimes markup extensions appear in markup as conventional elements.

공유 리소스Shared Resources

일부 XAML 페이지에는 동일한 값으로 설정하는 속성을 사용하는 여러 뷰가 포함됩니다.Some XAML pages contain several views with properties set to the same values. 예를 들어, 다음과 같이 Button 개체에 대한 대부분의 속성 설정은 동일합니다.For example, many of the property settings for these Button objects are the same:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

    <StackLayout>
        <Button Text="Do this!"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                BorderWidth="3"
                Rotation="-15"
                TextColor="Red"
                FontSize="24" />

        <Button Text="Do that!"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                BorderWidth="3"
                Rotation="-15"
                TextColor="Red"
                FontSize="24" />

        <Button Text="Do the other thing!"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                BorderWidth="3"
                Rotation="-15"
                TextColor="Red"
                FontSize="24" />

    </StackLayout>
</ContentPage>

해당 속성 중 하나를 변경해야 하는 경우, 세 번 보다는 한 번만 내용을 변경하는 것이 좋습니다.If one of these properties needs to be changed, you might prefer to make the change just once rather than three times. 코드라면 상수 및 정적(static) 읽기 전용 개체를 사용하여 해당 값을 일관되고 유지하고 쉽게 수정할 수 있습니다.If this were code, you’d likely be using constants and static read-only objects to help keep such values consistent and easy to modify.

XAML에서 한가지 인기있는 해결책은 해당 값이나 개체를 리소스 사전에 저장하는 것입니다.In XAML, one popular solution is to store such values or objects in a resource dictionary. VisualElement 클래스는 ResourceDictionary 유형의 Resources라는 속성을 정의합니다. 이는 string 유형의 키와 object 유형의 값을 가진 사전입니다.The VisualElement class defines a property named Resources of type ResourceDictionary, which is a dictionary with keys of type string and values of type object. 이 사전에 개체를 넣으면 모든 XAML 내에서 해당 개체를 태그로 참조할 수 있습니다.You can put objects into this dictionary and then reference them from markup, all in XAML.

한 페이지에서 리소스 사전을 사용하려면, 한 쌍의 Resources 속성 요소 태그를 포함합니다.To use a resource dictionary on a page, include a pair of Resources property-element tags. 다음과 같이 해당 페이지의 맨 위에 두는 것이 가장 유용합니다.It’s most convenient to put these at the top of the page:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

    <ContentPage.Resources>

    </ContentPage.Resources>
    ...
</ContentPage>

다음과 같이 ResourceDictionary 태그를 명시적으로 포함시켜야 합니다.It’s also necessary to explicitly include ResourceDictionary tags:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

    <ContentPage.Resources>
        <ResourceDictionary>

        </ResourceDictionary>
    </ContentPage.Resources>
    ...
</ContentPage>

이제 다양한 유형의 개체와 값을 리소스 사전에 추가할 수 있습니다.Now objects and values of various types can be added to the resource dictionary. 해당 유형은 인스턴스화할 수 있어야 합니다.These types must be instantiable. 예를 들어, 추상(abstract) 클래스는 추가할 수 없습니다.They can’t be abstract classes, for example. 해당 유형에는 매개 변수가 없는 공용(public) 생성자가 있어야 합니다.These types must also have a public parameterless constructor. 각 항목에는 x:Key 특성으로 지정된 사전 키가 필요합니다.Each item requires a dictionary key specified with the x:Key attribute. 예를 들어 다음과 같습니다.For example:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

    <ContentPage.Resources>
        <ResourceDictionary>
            <LayoutOptions x:Key="horzOptions"
                           Alignment="Center" />

            <LayoutOptions x:Key="vertOptions"
                           Alignment="Center"
                           Expands="True" />
        </ResourceDictionary>
    </ContentPage.Resources>
    ...
</ContentPage>

위 두 항목은 LayoutOptions 구조체 형식의 값이 있고, 각각은 고유 키 및 하나 또는 두 개의 속성 설정이 있습니다.These two items are values of the structure type LayoutOptions, and each has a unique key and one or two properties set. 코드 및 태그에서 LayoutOptions의 정적(static) 필드를 사용하는 것이 일반적이지만 여기서는 속성을 설정하는 것이 더 편리합니다.In code and markup, it’s much more common to use the static fields of LayoutOptions, but here it’s more convenient to set the properties.

이제 다음과 같이 단추의 HorizontalOptionsVerticalOptions 속성을 해당 리소스에 설정하면 해당 작업이 StaticResource XAML 태그 확장으로 완료됩니다.Now it’s necessary to set the HorizontalOptions and VerticalOptions properties of these buttons to these resources, and that’s done with the StaticResource XAML markup extension:

<Button Text="Do this!"
        HorizontalOptions="{StaticResource horzOptions}"
        VerticalOptions="{StaticResource vertOptions}"
        BorderWidth="3"
        Rotation="-15"
        TextColor="Red"
        FontSize="24" />

StaticResource 태그 확장은 중괄호로 구분 항상 및 사전 키를 포함합니다.The StaticResource markup extension is always delimited with curly braces, and includes the dictionary key.

StaticResource라는 이름은 Xamarin.Forms도 마찬가지로 지원하는 DynamicResource와 구별됩니다.The name StaticResource distinguishes it from DynamicResource, which Xamarin.Forms also supports. DynamicResource는 런타임 중에 변경 될 수 있는 값과 연결된 사전 키를 위한 것이고, StaticResource는 페이지 상의 요소가 생성될 때 한 번만 사전에서 요소를 접근합니다.DynamicResource is for dictionary keys associated with values that might change during runtime, while StaticResource accesses elements from the dictionary just once when the elements on the page are constructed.

BorderWidth 속성의 경우, 사전에 double 값을 저장할 필요가 있습니다.For the BorderWidth property, it’s necessary to store a double in the dictionary. 다음과 같이 XAML은 x:Doublex:Int32와 같은 공통 데이터 유형에 대한 태그를 편리하게 정의합니다.XAML conveniently defines tags for common data types like x:Double and x:Int32:

<ContentPage.Resources>
    <ResourceDictionary>
        <LayoutOptions x:Key="horzOptions"
                       Alignment="Center" />

        <LayoutOptions x:Key="vertOptions"
                       Alignment="Center"
                       Expands="True" />

        <x:Double x:Key="borderWidth">
            3
        </x:Double>
    </ResourceDictionary>
</ContentPage.Resources>

위에서처럼 세 줄에 추가할 필요는 없습니다.You don’t need to put it on three lines. 다음과 같이 해당 회전 각도에 대한 사전 항목은 한 줄만 차지합니다.This dictionary entry for this rotation angle only takes up one line:

<ContentPage.Resources>
    <ResourceDictionary>
        <LayoutOptions x:Key="horzOptions"
                       Alignment="Center" />

        <LayoutOptions x:Key="vertOptions"
                       Alignment="Center"
                       Expands="True" />

         <x:Double x:Key="borderWidth">
            3
         </x:Double>

        <x:Double x:Key="rotationAngle">-15</x:Double>
    </ResourceDictionary>
</ContentPage.Resources>

위의 두 리소스는 다음과 같이 LayoutOptions 값과 동일한 방식으로 참조할 수 있습니다.Those two resources can be referenced in the same way as the LayoutOptions values:

<Button Text="Do this!"
        HorizontalOptions="{StaticResource horzOptions}"
        VerticalOptions="{StaticResource vertOptions}"
        BorderWidth="{StaticResource borderWidth}"
        Rotation="{StaticResource rotationAngle}"
        TextColor="Red"
        FontSize="24" />

Color 유형의 리소스의 경우, 해당 유형의 특성을 직접 할당할 때 사용하는 것과 동일한 문자열 표현을 사용할 수 있습니다.For resources of type Color, you can use the same string representations that you use when directly assigning attributes of these types. 유형 변환기는 리소스가 생성될 때 호출됩니다.The type converters are invoked when the resource is created. 다음은 Color 유형 리소스입니다.Here's a resource of type Color:

<Color x:Key="textColor">Red</Color>

프로그램은 종종 FontSize 속성을 Large와 같은 NamedSize 열거형 멤버로 설정합니다.Often, programs set a FontSize property to a member of the NamedSize enumeration such as Large. FontSizeConverter 클래스는 배후에서 작동하여 Device.GetNamedSized 메서드를 사용하여 플랫폼 독립적인 값으로 변환합니다.The FontSizeConverter class works behind the scenes to convert it into a platform-dependent value using the Device.GetNamedSized method. 그러나 글꼴 크기 리소스를 정의할 때는 여기서 보는 바와 같이 x:Double로 숫자 값을 사용하는 것이 더 합리적입니다.However, when defining a font-size resource, it makes more sense to use a numeric value, shown here as an x:Double type:

<x:Double x:Key="fontSize">24</x:Double>

이제 Text를 제외한 모든 속성은 리소스 설정에 의해 정의됩니다.Now all the properties except Text are defined by resource settings:

<Button Text="Do this!"
        HorizontalOptions="{StaticResource horzOptions}"
        VerticalOptions="{StaticResource vertOptions}"
        BorderWidth="{StaticResource borderWidth}"
        Rotation="{StaticResource rotationAngle}"
        TextColor="{StaticResource textColor}"
        FontSize="{StaticResource fontSize}" />

또한 리소스 사전에서 OnPlatform을 사용하여 플랫폼 별로 다른 값을 정의할 수도 있습니다.It's also possible to use OnPlatform within the resource dictionary to define different values for the platforms. 다음은 OnPlatform 개체가 다른 텍스트 색상을 위한 리소스 사전의 일부가 되도록 하는 방법입니다.Here’s how an OnPlatform object can be part of the resource dictionary for different text colors:

<OnPlatform x:Key="textColor"
            x:TypeArguments="Color">
    <On Platform="iOS" Value="Red" />
    <On Platform="Android" Value="Aqua" />
    <On Platform="UWP" Value="#80FF80" />
</OnPlatform>

OnPlatform은 해당 개체가 사전에 있으므로 x:Key 특성을 얻고 제네릭 클래스이므로 x:TypeArguments 특성도 얻습니다.Notice that OnPlatform gets both an x:Key attribute because it’s an object in the dictionary and an x:TypeArguments attribute because it’s a generic class. iOS, AndroidUWP 특성은 개체가 초기화될 때 Color 값으로 변환됩니다.The iOS, Android, and UWP attributes are converted to Color values when the object is initialized.

다음은 여섯 개의 공유 값에 접근하는 세 개의 단추가 있는 완전한 최종 XAML 파일입니다.Here’s the final complete XAML file with three buttons accessing six shared values:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

    <ContentPage.Resources>
        <ResourceDictionary>
            <LayoutOptions x:Key="horzOptions"
                           Alignment="Center" />

            <LayoutOptions x:Key="vertOptions"
                           Alignment="Center"
                           Expands="True" />

            <x:Double x:Key="borderWidth">3</x:Double>

            <x:Double x:Key="rotationAngle">-15</x:Double>

            <OnPlatform x:Key="textColor"
                        x:TypeArguments="Color">
                <On Platform="iOS" Value="Red" />
                <On Platform="Android" Value="Aqua" />
                <On Platform="UWP" Value="#80FF80" />
            </OnPlatform>

            <x:Double x:Key="fontSize">24</x:Double>
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout>
        <Button Text="Do this!"
                HorizontalOptions="{StaticResource horzOptions}"
                VerticalOptions="{StaticResource vertOptions}"
                BorderWidth="{StaticResource borderWidth}"
                Rotation="{StaticResource rotationAngle}"
                TextColor="{StaticResource textColor}"
                FontSize="{StaticResource fontSize}" />

        <Button Text="Do that!"
                HorizontalOptions="{StaticResource horzOptions}"
                VerticalOptions="{StaticResource vertOptions}"
                BorderWidth="{StaticResource borderWidth}"
                Rotation="{StaticResource rotationAngle}"
                TextColor="{StaticResource textColor}"
                FontSize="{StaticResource fontSize}" />

        <Button Text="Do the other thing!"
                HorizontalOptions="{StaticResource horzOptions}"
                VerticalOptions="{StaticResource vertOptions}"
                BorderWidth="{StaticResource borderWidth}"
                Rotation="{StaticResource rotationAngle}"
                TextColor="{StaticResource textColor}"
                FontSize="{StaticResource fontSize}" />

    </StackLayout>
</ContentPage>

스크린샷은 일관된 스타일 및 플랫폼별 스타일 지정을 다음과 같이 보여줍니다.The screenshots verify the consistent styling, and the platform-dependent styling:

페이지의 상단에 Resources 컬렉션을 정의하는 것이 가장 일반적이지만, Resources 속성은 VisualElement에 의해 정의되고, 페이지의 다른 요소에서 Resources 컬렉션을 사용할 수도 있습니다.Although it is most common to define the Resources collection at the top of the page, keep in mind that the Resources property is defined by VisualElement, and you can have Resources collections on other elements on the page. 예를 들어, 다음과 같이 StackLayout에 하나를 추가해 봅니다.For example, try adding one to the StackLayout in this example:

<StackLayout>
    <StackLayout.Resources>
        <ResourceDictionary>
            <Color x:Key="textColor">Blue</Color>
        </ResourceDictionary>
    </StackLayout.Resources>
    ...
</StackLayout>

버튼의 텍스트 색상이 파란색임을 이제 알 수 있습니다.You’ll discover that the text color of the buttons is now blue. 기본적으로 XAML 파서가 StaticResource 태그 확장을 발견하면 시각적 트리를 검색하여 해당 키가 포함된 첫 번째 ResourceDictionary를 사용합니다.Basically, whenever the XAML parser encounters a StaticResource markup extension, it searches up the visual tree and uses the first ResourceDictionary it encounters containing that key.

리소스 사전에 저장된 가장 일반적인 유형 중 하나는 속성 설정 컬렉션을 정의하는 Xamarin.Forms Style 입니다.One of the most common types of objects stored in resource dictionaries is the Xamarin.Forms Style, which defines a collection of property settings. 스타일은 스타일 문서에 설명되어 있습니다.Styles are discussed in the article Styles.

가끔 XAML을 처음 접하는 개발자는 LabelButton 또는 ResourceDictionary와 같은 시각적 요소를 넣을 수 있는지 궁금해 합니다.Sometimes developers new to XAML wonder if they can put a visual element such as Label or Button in a ResourceDictionary. 물론 가능은 하지만 별로 의미가 없습니다.While it’s surely possible, it doesn’t make much sense. ResourceDictionary의 목적은 개체를 공유하는 것입니다.The purpose of the ResourceDictionary is to share objects. 시각적 요소는 공유할 수 없습니다.A visual element cannot be shared. 동일한 인스턴스가 한 페이지에 두 번 나타날 수 없습니다.The same instance cannot appear twice on a single page.

x:Static 태그 확장The x:Static Markup Extension

해당 이름의 유사성에도 불구 하 고 x:StaticStaticResource 는 매우 다릅니다.Despite the similarities of their names, x:Static and StaticResource are very different. StaticResource 는 리소스 사전에서 개체를 반환하는 반면 x:Static은 다음 중 하나에 액세스합니다.StaticResource returns an object from a resource dictionary while x:Static accesses one of the following:

  • 공용(public) 정적(static) 필드a public static field
  • 공용 정적 속성a public static property
  • 공용 상수 필드a public constant field
  • 열거형 멤버입니다.an enumeration member.

StaticResource 태그 확장은 리소스 사전을 정의하는 XAML 구현에 의해 지원되는 반면, x:Staticx 접두사가 드러내는 것처럼 XAML의 본질적인 부분입니다.The StaticResource markup extension is supported by XAML implementations that define a resource dictionary, while x:Static is an intrinsic part of XAML, as the x prefix reveals.

다음은 x:Static이 정적 필드 및 열거형 멤버를 명시적으로 참조할 수 있는 방법을 보여주는 몇 가지 예제입니다.Here are a few examples that demonstrate how x:Static can explicitly reference static fields and enumeration members:

<Label Text="Hello, XAML!"
       VerticalOptions="{x:Static LayoutOptions.Start}"
       HorizontalTextAlignment="{x:Static TextAlignment.Center}"
       TextColor="{x:Static Color.Aqua}" />

지금까지는 별로 인상적이지 않습니다.So far, this is not very impressive. 하지만 x:Static 태그 확장은 정적 필드나 속성을 자신의 코드에서 참조할 수도 있습니다.But the x:Static markup extension can also reference static fields or properties from your own code. 예를 들어, 다음은 응용 프로그램 전체에서 여러 페이지에 사용할 수 있는 정적 필드가 포함된 AppConstants 클래스입니다.For example, here’s an AppConstants class that contains some static fields that you might want to use on multiple pages throughout an application:

using System;
using Xamarin.Forms;

namespace XamlSamples
{
    static class AppConstants
    {
        public static readonly Thickness PagePadding;

        public static readonly Font TitleFont;

        public static readonly Color BackgroundColor = Color.Aqua;

        public static readonly Color ForegroundColor = Color.Brown;

        static AppConstants()
        {
            switch (Device.RuntimePlatform)
            {
                case Device.iOS:
                    PagePadding = new Thickness(5, 20, 5, 0);
                    TitleFont = Font.SystemFontOfSize(35, FontAttributes.Bold);
                    break;

                case Device.Android:
                    PagePadding = new Thickness(5, 0, 5, 0);
                    TitleFont = Font.SystemFontOfSize(40, FontAttributes.Bold);
                    break;

                case Device.UWP:
                    PagePadding = new Thickness(5, 0, 5, 0);
                    TitleFont = Font.SystemFontOfSize(50, FontAttributes.Bold);
                    break;
            }
        }
    }
}

XAML 파일에서 해당 클래스의 정적 필드를 참조하려면 XAML 파일에서 해당 파일의 위치를 나타내는 몇 가지 방법이 필요합니다.To reference the static fields of this class in the XAML file, you’ll need some way to indicate within the XAML file where this file is located. XML 네임 스페이스 선언을 사용하면 됩니다.You do this with an XML namespace declaration.

표준 Xamarin.Forms XAML 템플릿의 일부로 생성된 XAML 파일에는 다음과 같이 Xamarin.Forms 클래스에 접근하기 위한 XML 선언과 XAML에 고유한 태그 및 특성을 참조하는 두 개의 XML 네임 스페이스 선언이 포함되어 있습니다.Recall that the XAML files created as part of the standard Xamarin.Forms XAML template contain two XML namespace declarations: one for accessing Xamarin.Forms classes and another for referencing tags and attributes intrinsic to XAML:

xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

다른 클래스에 접근하려면 XML 네임 스페이스 선언이 필요합니다.You’ll need additional XML namespace declarations to access other classes. 각 추가 XML 네임 스페이스 선언은 새 접두사를 정의합니다.Each additional XML namespace declaration defines a new prefix. AppConstants와 같은 공유 응용 프로그램 .NET Standard 라이브러리의 로컬 클래스에 접근하려면, XAML 프로그래머는 종종 local 접두사를 사용합니다.To access classes local to the shared application .NET Standard library, such as AppConstants, XAML programmers often use the prefix local. 네임 스페이스 선언은 CLR (Common Language Runtime, 공용 언어 런타임) 네임 스페이스 이름(.NET 네임 스페이스 이름이라고도 함)을 나타내야 합니다. 해당 네임 스페이스 이름은 C# namespace 정의 또는 using 지시문에 나타나는 이름입니다.The namespace declaration must indicate the CLR (Common Language Runtime) namespace name, also known as the .NET namespace name, which is the name that appears in a C# namespace definition or in a using directive:

xmlns:local="clr-namespace:XamlSamples"

.NET Standard 라이브러리를 참조 하는 모든 어셈블리에서.NET 네임 스페이스에 대 한 XML 네임 스페이스 선언을 정의할 수도 있습니다.You can also define XML namespace declarations for .NET namespaces in any assembly that the .NET Standard library references. 예를 들어, 다음은 표준 .NET System 네임 스페이스에 대한 sys 접두사입니다. 해당 네임 스페이스는 다음과 같이 mscorlib 어셈블리에 있으며, 한때 "Microsoft 공용 개체 런타임 라이브러리(Microsoft Common Object Runtime Library)"를 나타냈지만 이제 "다국어 표준 개체 런타임 라이브러리(Multilanguage Standard Common Object Runtime Library)"를 의미합니다.For example, here’s a sys prefix for the standard .NET System namespace, which is in the mscorlib assembly, which once stood for "Microsoft Common Object Runtime Library," but now means "Multilanguage Standard Common Object Runtime Library." 다른 어셈블리 이기 때문에 지정 해야 어셈블리 이름을 여기서 mscorlib:Because this is another assembly, you must also specify the assembly name, in this case mscorlib:

xmlns:sys="clr-namespace:System;assembly=mscorlib"

키워드 clr-namespace 뒤에 콜론이 오고, 그 다음 .NET 네임 스페이스 이름, 세미콜론, 키워드 assembly, 등호 및 어셈블리 이름이 옵니다.Notice that the keyword clr-namespace is followed by a colon and then the .NET namespace name, followed by a semicolon, the keyword assembly, an equal sign, and the assembly name.

맞습니다, 콜론은 clr-namespace 뒤에 오지만 등호는 assembly 다음에 옵니다.Yes, a colon follows clr-namespace but equal sign follows assembly. 구문은이 방식으로 의도적으로 정의 되었습니다. 대부분의 XML 네임 스페이스 선언을 참조와 같은 URI 체계 이름을 시작 하는 URI http에 항상 뒤에 콜론입니다.The syntax was defined in this way deliberately: Most XML namespace declarations reference a URI that begins a URI scheme name such as http, which is always followed by a colon. 해당 문자열의 clr-namespace 부분은 URI 규칙을 모방하기 위함입니다.The clr-namespace part of this string is intended to mimic that convention.

해당 네임 스페이스 선언은 모두 StaticConstantsPage 샘플에 포함됩니다.Both these namespace declarations are included in the StaticConstantsPage sample. BoxView 차원은 Math.PIMath.E로 설정되어 있지만 100의 비율로 배율이 조정됩니다.Notice that the BoxView dimensions are set to Math.PI and Math.E, but scaled by a factor of 100:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             x:Class="XamlSamples.StaticConstantsPage"
             Title="Static Constants Page"
             Padding="{x:Static local:AppConstants.PagePadding}">

    <StackLayout>
       <Label Text="Hello, XAML!"
              TextColor="{x:Static local:AppConstants.BackgroundColor}"
              BackgroundColor="{x:Static local:AppConstants.ForegroundColor}"
              Font="{x:Static local:AppConstants.TitleFont}"
              HorizontalOptions="Center" />

      <BoxView WidthRequest="{x:Static sys:Math.PI}"
               HeightRequest="{x:Static sys:Math.E}"
               Color="{x:Static local:AppConstants.ForegroundColor}"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand"
               Scale="100" />
    </StackLayout>
</ContentPage>

결과의 크기 BoxView 화면을 기준으로 플랫폼에 따라 다릅니다.The size of the resultant BoxView relative to the screen is platform-dependent:

기타 표준 태그 확장Other Standard Markup Extensions

여러 태그 확장은 XAML에 고유하며 Xamarin.Forms XAML 파일에 지원됩니다.Several markup extensions are intrinsic to XAML and supported in Xamarin.Forms XAML files. 이 중 몇 가지는 자주 사용되지 않지만 필요할 때는 기본적입니다.Some of these are not used very often but are essential when you need them:

  • 속성은 기본적으로 null이 아닌 값을 갖지만, null로 설정하고자 한다면 {x:Null} 태그 확장으로 설정합니다.If a property has a non- null value by default but you want to set it to null, set it to the {x:Null} markup extension.
  • 속성이 Type 형식인 경우, {x:Type someClass}를 사용하여 해당 속성을 Type 개체에 할당할 수 있습니다.If a property is of type Type, you can assign it to a Type object using the markup extension {x:Type someClass}.
  • XAML의 배열은 x:Array 태그 확장을 사용하여 정의할 수 있습니다.You can define arrays in XAML using the x:Array markup extension. 이 태그 확장에는 배열에 있는 요소 유형을 나타내는 Type이라는 필수 특성이 있습니다.This markup extension has a required attribute named Type that indicates the type of the elements in the array.
  • Binding 태그 확장에 대해서는 설명 4부. 데이터 바인딩 기본 사항에서 논의합니다.The Binding markup extension is discussed in Part 4. Data Binding Basics.

ConstraintExpression 태그 확장The ConstraintExpression Markup Extension

태그 확장은 속성을 가질 수 있지만, XML 특성처럼 설정되지는 않습니다.Markup extensions can have properties, but they are not set like XML attributes. 태그 확장에서 속성 설정은 쉼표로 구분하며 중괄호 내에서 따옴표는 표시되지 않습니다.In a markup extension, property settings are separated by commas, and no quotation marks appear within the curly braces.

이것은 RelativeLayout 클래스와 함께 사용되는 ConstraintExpression이라는 Xamarin.Forms 태그 확장을 사용하여 설명할 수 있습니다.This can be illustrated with the Xamarin.Forms markup extension named ConstraintExpression, which is used with the RelativeLayout class. 자식 뷰의 위치나 크기를 상수로 지정하거나 부모 또는 다른 명명 된 뷰와 상대적으로 지정할 수 있습니다.You can specify the location or size of a child view as a constant, or relative to a parent or other named view. ConstraintExpression의 구문은 Factor와 다른 뷰의 속성에 Constant를 곱한 값을 사용하여 뷰의 위치나 크기를 설정할 수 있습니다.The syntax of the ConstraintExpression allows you set the position or size of a view using a Factor times a property of another view, plus a Constant. 그것보다 더 복잡한 것은 코드가 필요합니다.Anything more complex than that requires code.

예를 들면 다음과 같습니다.Here’s an example:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.RelativeLayoutPage"
             Title="RelativeLayout Page">

    <RelativeLayout>

        <!-- Upper left -->
        <BoxView Color="Red"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=Constant,
                                            Constant=0}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=Constant,
                                            Constant=0}" />
        <!-- Upper right -->
        <BoxView Color="Green"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Width,
                                            Factor=1,
                                            Constant=-40}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=Constant,
                                            Constant=0}" />
        <!-- Lower left -->
        <BoxView Color="Blue"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=Constant,
                                            Constant=0}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Height,
                                            Factor=1,
                                            Constant=-40}" />
        <!-- Lower right -->
        <BoxView Color="Yellow"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Width,
                                            Factor=1,
                                            Constant=-40}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Height,
                                            Factor=1,
                                            Constant=-40}" />

        <!-- Centered and 1/3 width and height of parent -->
        <BoxView x:Name="oneThird"
                 Color="Red"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Width,
                                            Factor=0.33}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Height,
                                            Factor=0.33}"
                 RelativeLayout.WidthConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Width,
                                            Factor=0.33}"
                 RelativeLayout.HeightConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Height,
                                            Factor=0.33}"  />

        <!-- 1/3 width and height of previous -->
        <BoxView Color="Blue"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=RelativeToView,
                                            ElementName=oneThird,
                                            Property=X}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=RelativeToView,
                                            ElementName=oneThird,
                                            Property=Y}"
                 RelativeLayout.WidthConstraint=
                     "{ConstraintExpression Type=RelativeToView,
                                            ElementName=oneThird,
                                            Property=Width,
                                            Factor=0.33}"
                 RelativeLayout.HeightConstraint=
                     "{ConstraintExpression Type=RelativeToView,
                                            ElementName=oneThird,
                                            Property=Height,
                                            Factor=0.33}"  />
    </RelativeLayout>
</ContentPage>

아마도이 샘플에서 수행 해야 하는 가장 중요 한과 태그 확장의 구문: 태그 확장의 중괄호 안의 하지 인용 부호 표시 되어야 합니다.Perhaps the most important lesson you should take from this sample is the syntax of the markup extension: No quotation marks must appear within the curly braces of a markup extension. XAML 파일에 태그 확장을 입력할 때 속성의 값을 자연스럽게 따옴표로 묶고 싶을 것입니다.When typing the markup extension in a XAML file, it is natural to want to enclose the values of the properties in quotation marks. 유혹을 이겨내십시오!Resist the temptation!

실행 중인 프로그램이 다음과 같습니다.Here’s the program running:

요약Summary

문서에 표시된 XAML 태그 확장은 XAML 파일에 대한 중요한 지원을 제공합니다.The XAML markup extensions shown here provide important support for XAML files. 하지만 가장 중요 한 XAML 태그 확장은 아마도 Binding,이 시리즈의 다음 부분에 나와 있는 4 부입니다. 데이터 바인딩 기본 사항에서 논의합니다.But perhaps the most valuable XAML markup extension is Binding, which is covered in the next part of this series, Part 4. Data Binding Basics.