2016년 9월 22일 목요일

Xamarin.Forms XAML Basics Part 1, Getting Started with XAML

Xamarin.Forms에서의 XAML 사용이 궁금해서 아래 링크를 보며 대충 필요한 것만 정리함.
https://developer.xamarin.com/guides/xamarin-forms/xaml/

XAML Basics

https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/


Xarmarin 장단점

장점
- 코드에 비해 명료하여 읽고 이해하기 쉬움
- XML 형식을 따르므로 UI 객체의 상속구조를 표현할 수 있음.

단점
- Layout만을 표현하므로 이벤트 핸들러는 코드에서 처리 되어야 한다.
- XAML은 ListView와 같이 반복적인 동작(loop)은 포함할 수 없다.
- XAML은 conditional processing을 포함할 수 없어 조건에 따라 동적으로 layout을 변경할 수 없다.
- XAML은 일반적으로 파라미터를 가지는 생성자를 가진 객체의 인스턴스화를 할 수 없다. (방법은 있다고 함.)
- XAML은 일반적으로 method를 호출할 수 없다. (방법은 있다고 함.)

XAML은 일반적으로 XML이지만 아래의 특성을 가진다.
- Property elements
- Attached properties
- Markup extensions

Part 1. Getting Started with XAML

https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/getting_started_with_xaml/


Anatomy of a XAML Class

- XAML 파일(xxx.xaml) 생성 시 xxx.xaml.cs가 함께 생성 됨.
  xxx.xaml.cs는 C# code 파일로서 XAML file과 함께 xxx class 정의를 위해 사용됨.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.HelloXamlPage">
</ContentPage>

XML의 namespace는 기본적으로 Xamarin.Forms와 x로 지정된 MS의 XAML specification(https://msdn.microsoft.com/en-us/library/ff629155.aspx)을 따르고 있음.

x:Class로 XAML 파일이 인스턴스화 될 class 이름이고 XamlSamples namespace의 HelloXamlPage class 임을 말하고 있다.

HelloXamlPage.xaml.cs 를 보면 다음과 같다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XamlSamples
{
    public partial class HelloXamlPage
    {
        public HelloXamlPage()
        {
            InitializeComponent();
        }
    }
}
눈여겨 봐야할 부분은 HelloXamlPage class가 partial로 정의 되어 있어 다른 곳에 부분적인 class 정의가 있음을 명시하고 있는 점과 ContentPage를 상속받지 않는다는 점이다.

일단 HelloXamlPage를 main page로 아래와 같이 설정하고 컴파일을 해보자.
namespace XamlSamples
{
    public class App : Xamarin.Forms.Application
    {
        public App ()
        {
            MainPage = new HelloXamlPage();
        }
    }
}
 Build-Deply-Run 주기에서 XAML 파일은 두번 parsing된다. building 시점에 한번 parsing되고 runtime 시점에 전체 XAML 파일이 Portable Code Library DLL에 binding되고 parsing 된다.

빌드 시점에 XAML 파일은 C# code file을 obj/Debug 폴더에 다음과 같은 HelloXamlPage.xaml.g.cs 이름으로 생성한다. (.g. = generate 의미)

namespace XamlSamples {
    using System;
    using Xamarin.Forms;
    using Xamarin.Forms.Xaml;

    public partial class HelloXamlPage : ContentPage {

        private void InitializeComponent() {
            this.LoadFromXaml(typeof(HelloXamlPage));
        }
    }
}

HelloXamlPage class의 다른 정의 부분이고 HelloXamlPage가 ContentPage를 상속하고 HelloXamlPage.xaml.cs에서 호출하는 InitiailzeComponent()를 정의하고 함수내에서 Xaml을 로드함을 알 수 있다.

즉 runtime 시 각 platform project들은 초기화면을 구성하기 위해 App.GetMainPage를 호출하고 그 때 HelloXamlPage class가 instance화 된다. instance 시 생성자가 호출되며 InitialzeComponet가 호출되고 XAML파일을 로드하여 main page를 보여주게 된다.

XAML로드 시점인 LoadFromXaml() 호출 시 XAML exception들(Xamarin.Forms.Xaml.XamlParseException)이 발생이 될 수 있다.

XAML and Code Interactions
: https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/getting_started_with_xaml/#XAML_and_Code_Interactions

기본 코드 : Stack Layout내에 Slider, Label, Button이 존재함.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.XamlPlusCodePage"
             Title="XAML + Code Page">
  <StackLayout>
    <Slider VerticalOptions="CenterAndExpand" />

    <Label Text="A simple Label"
           Font="Large"
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand" />

    <Button Text="Click Me!"
            HorizontalOptions="Center"
            VerticalOptions="CenterAndExpand" />
  </StackLayout>
</ContentPage>

Part 4. Data Binding Basics(https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_binding_basics/)와 같이 XAML과 data binding을 통해서 Slider와 Label을 처리할 수 있지만 지금은 toturial이므로 XAML에서 handler를 hardcoding하여 code에서 처리하는 예제임.

XamlPlusCodePage.xaml.cs에서 slider와 button의 event들을 처리할 method들을 정의. event handler들이고 XAML에서 호출하는 것은 동일 class이므로 public으로 정의할 필요는 없음.
namespace XamlSamples
{
    public partial class XamlPlusCodePage
    {
        public XamlPlusCodePage()
        {
            InitializeComponent();
        }

        void OnSliderValueChanged(object sender,
                                  ValueChangedEventArgs args)
        {

        }

        void OnButtonClicked(object sender, EventArgs args)
        {

        }
    }
}

위 Xaml에서 Slider, Button에 각 event에 대한 method를 지정
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.XamlPlusCodePage"
             Title="XAML + Code Page">
  <StackLayout>
    <Slider VerticalOptions="CenterAndExpand"
            ValueChanged="OnSliderValueChanged" />

    <Label Text="A simple Label"
           Font="Large"
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand" />

    <Button Text="Click Me!"
            HorizontalOptions="Center"
            VerticalOptions="CenterAndExpand"
            Clicked="OnButtonClicked" />
  </StackLayout>
</ContentPage>

Slider의 변경에 따라서 Label을 변경하려고 할 때 Code에서 Label을 지정하여 변경할 수 있어야 한다. 이 때 XAML의 x:Name와 같은 이름의 객체를 이용하여 사용하게 되므로 XAML에서 x:Name을 지정해 줘야 한다.

<Label x:Name="valueLabel"
       Text="A simple Label"
       Font="Large"
       HorizontalOptions="Center"
       VerticalOptions="CenterAndExpand" />
또한 Slider의 OnSliderValueChanged handler를 통해 Slider의 값이 args를 통해 전달 되어 이를 세자리 Float 형식의 string으로 만들어 valueLabel의 Text로 지정한다.
void OnSliderValueChanged(object sender,
                          ValueChangedEventArgs args)
{
    valueLabel.Text = args.NewValue.ToString("F3");
}

Button이 클릭 될 경우 button의 text를 alert창으로 보여줄 것이고 코드는 다음과 같음.
async void OnButtonClicked(object sender, EventArgs args)
{
    Button button = (Button)sender;
    await DisplayAlert("Clicked!",
        "The button labeled '" + button.Text + "' has been clicked",
        "OK");
}

async 지시자는 DisplayAlert method가 비동기적으로 실행되어야 하는 부분인 await operator가 선언된 부분이 있음을 알리는 것이고 해당 부분은 비동기적으로 수행되므로 block 될 수 있음을 염두해야 한다.

설명한 것을 정리하면 XAML에서 발생된 event는 code-behind 파일의 event handler에서 처리 될 수 있다는 것과 XAML과 code-behind file간 interaction은 XAML에서 명시된 x:Name attribute를 통해서 해당 object에 접근할 수 있다는 것이 interaction의 주요 내용으로 보임.

한가지 팁은 XamlPlugCode.xaml.g.cs 에서 x:Name attribute의 object를 private field로 지정해서 사용할 수 있는 점이다.
public partial class XamlPlusCodePage : ContentPage {

    private Label valueLabel;

    private void InitializeComponent() {
        this.LoadFromXaml(typeof(XamlPlusCodePage));
        valueLabel = this.FindByName<Label>("valueLabel");
    }
}
이런 경우 valueLevel을 접근하기 위해 private field를 언제든 사용가능하다는 것과 접근할 때 마다 parsing이 필요 없다는 점이 장점이다.


댓글 없음:

댓글 쓰기