Pages

Sunday, June 30, 2019

Compiled binding: the performance booster you should know


In the traditional binding (classic binding), reflection is used to get the binding information, this process is costly in terms of performance, as it’s conducted in run-time.

Now Xamarin introduces a nice alternative to the classic binding, official docs says that resolving compiled binding is 8 to 20 times quicker than classic binding- a big deal!

Here’s how to enable compiled binding:

  1. First enable XamlCompilation, by adding this attribute to your xaml class:

  2. [XamlCompilation(XamlCompilationOptions.Compile)]
    You can also enable it at the assembly level.
  3. In the root element of your xaml (where you set the BindingContext on) define the x:DataType and set it to your view model (a string -not markup extension):

Example:
Code behind:


[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainPage : ContentPage
{
    ...
}

XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:vm="clr-namespace:MyXam.ViewModels"
             x:Class="MyXam.MainPage"
             x:DataType="vm:MainViewModel">
    <ContentPage.BindingContext>
        <vm:MainViewModel/>
    </ContentPage.BindingContext>
    <Grid>
        <Entry Text="{Binding SingleItem.Name}" Grid.Row="0"/>
        ...
    </Grid>
</ContentPage>

one exception for this is when you use DataTemplate (in a ListView for example) where the BindingContext of the DataTemplate becomes a singular object from the ItemsSource collection, you'll need to define x:DataType on the DataTemplate:


<Grid>
    <Entry Text="{Binding SingleItem.Name}" Grid.Row="0"/>
    
    <ListView ItemsSource="{Binding Items}" Grid.Row="1">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="local:Item">
                <ViewCell>
                    <StackLayout>
                        <Label Text="{Binding Name}"/>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

Here's why you should consider compiled binding in your next project:
  1. You get compile-time errors for invalid binding expressions
  2. Faster compilation.
It’s recommended over classic binding, and for existing projects you can switch to compiled binding easily.

Saturday, June 29, 2019

You never needed to define ColumnDefinitions and RowDefinitions in your Grid

So, I was reading through a topic in docs, and one of the samples has a Grid, but that Grid looked sleek and neat that I'm not familiar with, it didn't have the <ColumnDefinitions> and <RowDefinitions> tags, children defines their position in the Grid as normal by the attached properties Grid.Column and Grid.Row, and the Grid does the positioning without the need of precedent definitions of rows and columns, for example if you need to accomplish this design:


You can write this:

<Grid>
    <Grid ColumnSpacing="0" RowSpacing="0" Grid.ColumnSpan="3">
        <Label Grid.Row="0" Grid.Column="0" BackgroundColor="Red">A</Label>
        <Label Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" BackgroundColor="Green">B</Label>
        <Label Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" BackgroundColor="Blue">C</Label>
        <Label Grid.Row="1" Grid.Column="2" Grid.RowSpan="2" BackgroundColor="Yellow">D</Label>
        <Label Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" BackgroundColor="Purple">E</Label>
    </Grid>
    <BoxView Grid.Column="3"/>
    <BoxView Grid.Row="1"/>
</Grid>

It will look through the attached properties and compute the needed columns and rows, for example the highest Grid.Column value for the outer Grid is 3, thus it has 4 columns, similarly, the highest Grid.Row value is 1 thus it has 2 rows.

You don't need to write all this:


<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Grid ColumnSpacing="0" RowSpacing="0" Grid.ColumnSpan="3">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Label Grid.Row="0" Grid.Column="0" BackgroundColor="Red">A</Label>
        <Label Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" BackgroundColor="Green">B</Label>
        <Label Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" BackgroundColor="Blue">C</Label>
        <Label Grid.Row="1" Grid.Column="2" Grid.RowSpan="2" BackgroundColor="Yellow">D</Label>
        <Label Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" BackgroundColor="Purple">E</Label>
    </Grid>
    <BoxView Grid.Column="3"/>
    <BoxView Grid.Row="1"/>
</Grid>

Look how much code you saved, this is so satisfying!
Please note that we can benefit from this auto-definitions only when we don't have customized columns and rows (i.e., defining Width for columns and Height for rows).

Monday, June 24, 2019

Loading async data in the constructor of the view model in Xamarin

Whenever I have a page that loads data once constructed I start to baffle about how to do the async work in the constructor? I posted a question on Stackoverflow to know how other fellows cope with this dilemma, one commented that I can create an event for that and fire it in the constructor, the event handler can be async, so problem solved- in an ugly workaround, I mean, really! create event to call other method in the same class? don't blame async!

Until I watched this Channel9 episode , the guest (Brandon Minnick) suggested a nice workaround, that fits closely to the MVVM pattern:
Create a command that loads the data in its execute function (that can be async), and in constructor of the view model, we can just do LoadCommand.Execute(null); //done.

and this is really nice solution, I see commands as the MVVM's capsules of data, so putting some work in them is very reasonable, off course if the work isn't async there's no point encapsulating it in a command unless you want to share the same work between views.. but using them to be able to run async from constructor is not costly/ ugly solution.

How to do code reviews correctly

Introduction Code review is a special event in the life cycle of software development, it's where ownership is transferred from the deve...