Different types of bindings in Web Atoms for Xamarin.Forms
Tags: xamarin, xamarinforms, typescript, showdev
Published: 2020-04-04 05:57:38

# Types of Bindings

Web Atoms offers two types of data bindings. JavaScript Data Binding and CLR Dta Binding. CLR Data Binding refers to existing Binding mechanisms offered in Xamarin/WPF in Xaml.

# JavaScript Data Binding

Web Atoms framework provides Binding of JavaScript objects within JavaScript engine. This form of binding allows more features over CLR Data Binding. Data Binding in JavaScript allows you to rewrite custom expressions in JavaScript and you don't have to recompile your native app.

## Pros of JavaScript Data Binding

1. It can contain custom TypeScript expression
2. You can write unit tests in JavaScript to cover conversions
3. Smaller app size as all the code can live on server
4. String resources can live on the server leading to smaller app size
5. You can unit test your bindings with string resources in TypeScript

## Cons of JavaScript Data Binding

1. You cannot use CLR Value Converters
2. You cannot use it in Control Templates

### One Time JavaScript Binding

One time binding offers expression evaluation at later stage. As component is being built, not all properties are set at time of creation, order of property initialization is completely random.

```typescript
   <XF.Label
       text={Bind.oneTime( () => this.viewModel.label )}
       />
``` 

You can also do the same by typing,
```typescript
   <XF.Label
       text={this.viewModel.label}
       />
``` 
but it may fail as viewModel or label may not have been initialized.

### One Way JavaScript Binding

One way binding offers expression evaluation whenever any of referenced properties are updated.

```typescript
   <XF.Label
       text={Bind.oneWay(
           () => `${this.viewModel.firstName} ${this.viewModel.lastName}`)}
       />
``` 

The above example offers simple concatenation of first name and last name whenever any of them is modified. Doing same in C# apart from simple string operations usually requires separate converter and binding expressions becomes very complex.

#### Data Binding in items scope

```typescript
   <XF.CollectionView>
       <XF.CollectionView.itemTemplate>
          <XF.DataTemplate>
              <XF.Label
                  backgroundColor={Bind.oneWay(
                    (x) => this.selectedItem == x.data
                           ? Colors.lightGreen
                           : Colors.white
                    )}
                  text={Bind.oneWay((x) => x.data.label)}
                  />
          </XF.DataTemplate>
       </XF.CollectionView.itemTemplate>
   </XF.CollectionView>
``` 

In above example, every item of `CollectionView` receives an extra parameter `x` that refers to UI Element in collection. And `data` property of Element is the item in collection. Notice, that this expression can watch for changes in `this.selectedItem` as well as `x.data` (as `x.data` changes while item template is reused). This successfully changes color when selected item is updated.

So Data Binding can easily works at nested scopes without having to create complex named relations which are required in CLR Data Binding.

> So OneWay binding will watch for changes in any of `this.*.*....` expression and expression of type `x.*.*....` where `x` is first parameter of `Bind.oneWay` method.

#### Intellisense in `Bind.oneWay`

TypeScript with VS Code offers excellent intellisense, we can use it by declaring some interfaces.

```typescript

   const CustomerBinding = Bind.withData<ICustomer>;

   <XF.CollectionView>
       <XF.CollectionView.itemTemplate>
          <XF.DataTemplate>
              <XF.Label
                  backgroundColor={CustomerBinding.oneWay(
                    (x) => this.selectedItem == x.data
                           ? Colors.lightGreen
                           : Colors.white
                    )}
                  text={CustomerBinding.oneWay((x) => /* error */x.data.label)}
                  />
          </XF.DataTemplate>
       </XF.CollectionView.itemTemplate>
   </XF.CollectionView>

```

In above example, we get an error that there is no `label` on `ICustomer`. While typing `.` after `data` will immediately display list of properties/fields that exists inside interface `ICustomer`.

## Two Way JavaScript Binding

Web Atoms offers two way data binding same as in CLR.
```typescript
   <XF.SearchBar
       text={Bind.twoWays(() => this.viewModel.search)}
       />
```

# CLR Data Binding

Though JavaScript Data Binding is sufficient in many ways, it lacks ability to provide control over Control Templates.

You can write `ControlTemplate` in TSX, though you can use some JavaScript bindings but when you want to bind properties of Template Owner, you cannot do that with JavaScript.

But, You can create CLR `DataBinding` object, and it will work exactly in same way. Let's look at the `ControlTemplate` of `AtomForm` which allows you to change look and field of each field.

```typescript
<WA.AtomForm>
    <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>
    <WA.AtomField
        label="Username:"
        isRequired={true}
        error={Bind.oneWay(() => this.viewModel.errorUsername)}>
           <XF.Entry text={Bind.twoWays(() => this.viewModel.model.username)}/>
    </WA.AtomField>
    <WA.AtomField
        label="Password"
        isRequired={true}
        error={Bind.oneWay(() => this.viewModel.errorPassword)}>
        <XF.Entry
            isPassword={true}
            text={Bind.twoWays(() => this.viewModel.model.password)}
            />
    </WA.AtomField>
    <XF.Button
        command={Bind.event((s, e) => this.viewModel.signup())}
        text="Signup"/>
</WA.AtomForm>
```

In above example, you can see that `X.TemplateBinding` allows you to bind `Label` property of `TemplateOwner`. Similarly you can use `X.Binding` to bind CLR data objects.


Examples,

```typescript

   <XF.Label
       text={X.Binding("path")}

```

You cannot use CLR DataBinding to bind JavaScript objects, this is not limitation but it is unnecessary step as watching expressions for changes in CLR is more time consuming and requires complex expressions. We may improve this in future based on performance analysis. Currently keeping all bindings JavaScript makes it easy to debug as you can easily create HTML component and test it in browser.

## Pros of CLR Data Binding

1. You can use them in `ControlTemplate`
2. You can reuse ValueConverters that exists in your C# code.

## Cons of CLR Data Binding

1. You cannot use them to bind JavaScript objects
2. You cannot write unit test in JavaScript
3. You have to recompile and republish your app if you make changes to value converters

### Current Limitations

These are current limitations in TSX, however they will be added in future as we progress.

1. No `Style`
2. No `Trigger`

However, it seems that we can easily create `StyleSheet`.

## Xamarin Forms StyleSheet

```typescript

   // you can write style as template literal
   const style = `
     listview image {
        height: 60;
        width: 60;
     }

     stacklayout>image {
        height: 200;
        width: 200;
     }
   `;

    <XF.Grid>
       <XF.Grid.Resources>
           <XF.StyleSheet source={style}/>
       </XF.Grid.Resources>
    </XF.Grid>

```

> All Xamarin Components will automatically inherit whatever default Styles and StyleSheet you have added in `App.Resources`.

> So you can create a master style for your app and put it in your App. You can also dynamically load the content of style sheet for your app, so you don't have to recompile and republish your app.