How to write Templates in Xamarin.Forms with TypeScript?
Tags: xamarin, xamarinforms, typescript, showdev
Published: 2020-03-02 07:37:53

# List View

Same as in XAML, you can create `DataTemplate` easily in TSX as shown below, syntax is not very different then that of Xaml.

```typescript

import Bind from "@web-atoms/core/dist/core/Bind";
import XNode from "@web-atoms/core/dist/core/XNode";
import { AtomXFControl } from "@web-atoms/core/dist/xf/controls/AtomXFControl";
import XF from "@web-atoms/xf-controls/dist/clr/XF";
import AtomXFContentPage from "@web-atoms/xf-controls/dist/pages/AtomXFContentPage";
import ListViewModel from "./ListViewModel";

export default class List extends AtomXFContentPage {

    public viewModel: ListViewModel;

    public create() {
        this.viewModel = this.resolve(ListViewModel);

        this.render(
            <XF.ContentPage title="List Sample">
                <XF.ListView itemsSource={Bind.oneWay(() => this.viewModel.movies.value)}>
                    <XF.ListView.itemTemplate>
                        <XF.DataTemplate>
                            <XF.ViewCell>
                                <XF.Label text={Bind.oneWay((x) => x.data.name)}/>
                            </XF.ViewCell>
                        </XF.DataTemplate>
                    </XF.ListView.itemTemplate>
                </XF.ListView>
            </XF.ContentPage>
        );
    }

}
```

Same as that of Xaml, you can define `DataTemplate` with a `ViewCell` or any element that is derived from `Cell`

# Template Selector

Writing template selector requires little different syntax.

```typescript
        this.render(<XF.ContentPage title="List with Template Selector">
            <XF.ListView itemsSource={Bind.oneWay(() => this.viewModel.movies.value)}>
                <WA.AtomTemplateSelector.templateSelector>
                    <WA.AtomTemplateSelector selector={(d: IMovie) => /horror/i.test(d.genre)
                        ? 1 : 0}>
                        {/* Template 0 */}
                        <XF.DataTemplate>
                            <XF.TextCell
                                text={Bind.oneWay((x) => x.data.name)}
                                textColor="black"
                                />
                        </XF.DataTemplate>
                        {/* Template 1 */}
                        <XF.DataTemplate>
                            <XF.TextCell
                                text={Bind.oneWay((x) => x.data.name)}
                                textColor="red"
                                />
                        </XF.DataTemplate>
                    </WA.AtomTemplateSelector>
                </WA.AtomTemplateSelector.templateSelector>
            </XF.ListView>
        </XF.ContentPage>);
```

As you can see, `WA.AtomTemplateSelector` is a placeholder element, which will simply set template based on some condition.

`selector` condition evaluates and returns an index of templates enclosed within `AtomTemplateSelector`.

# Collection View

In collection view, you can write templates without cells, same as in Xaml.

```typescript
   <XF.CollectionView 
       itemsSource={Bind.oneWay(() => this.viewModel.movies.value)}>
       <XF.CollectionView.itemTemplate>
            <XF.DataTemplate>
                <XF.Label text={Bind.oneWay((x) => x.data.name)}/> 
            </XF.DataTemplate>
       </XF.CollectionView.itemTemplate>
   </XF.CollectionView>
```


# How does it work?

`XF.DataTemplate` translates to `Xamarin.Forms.DataTemplate` and it uses constructor with factory to create elements only when needed.

# How to create control template?

Creating control template is exactly same with little difference in CLR Xamarin binding syntax.

Following example displays, how to change `ControlTemplate` of `AtomField` in form.

```typescript
   <WA.AtomForm.fieldStyle>
      <XF.ControlTemplate>
         <XF.Grid>
            <XF.Grid.rowDefinitions>
               <XF.RowDefinition height="Auto"/>
                  <XF.RowDefinition/>
                  <XF.RowDefinition height="Auto"/>
            </XF.Grid.rowDefinitions>
            <XF.Label
               text={X.TemplateBinding("Label")}
               textColor="Green"
               />
            <XF.ContentPresenter
               { ... XF.Grid.row(1)}
               />
         </XF.Grid>
     </XF.ControlTemplate>
   </WA.AtomForm.fieldStyle>
```

`Binding` of Xamarin.Forms is actually replaced with `X.Binding` and `X.TemplateBinding`.

In above example, `XF.ControlTemplate` refers to `ControlTemplate` of Xamarin.Forms. Templates are optimized to be reused and there is no performance lag even when they are written in TypeScript.

# Interoperability

Web Atoms allows you to use, both JavaScript as well as Xamarin Bindings on `TemplateBinding` as well as `Binding`. However, little care must be taken based on source object. To bind properties of classes written in C# you must use `X.Binding` and `X.TemplateBinding` respectively. To bind objects created in JavaScript, you must use `Bind.oneWay/twoWays` syntax.