Different types of bindings in Web Atoms for Xamarin.Forms

akashkava

Akash Kava

Posted on April 4, 2020

Different types of bindings in Web Atoms for Xamarin.Forms

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.

   <XF.Label
       text={Bind.oneTime( () => this.viewModel.label )}
       />
Enter fullscreen mode Exit fullscreen mode

You can also do the same by typing,

   <XF.Label
       text={this.viewModel.label}
       />
Enter fullscreen mode Exit fullscreen mode

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.

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

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

   <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>
Enter fullscreen mode Exit fullscreen mode

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.


   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>

Enter fullscreen mode Exit fullscreen mode

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.

   <XF.SearchBar
       text={Bind.twoWays(() => this.viewModel.search)}
       />
Enter fullscreen mode Exit fullscreen mode

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.

<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>
Enter fullscreen mode Exit fullscreen mode

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,


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

Enter fullscreen mode Exit fullscreen mode

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


   // 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>

Enter fullscreen mode Exit fullscreen mode

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.

💖 💪 🙅 🚩
akashkava
Akash Kava

Posted on April 4, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related