Xamarin Forms: Embedding native controls and still have XAML compilation for the Page

Embedding native controls

Skip this part if you know what the embedding native controls is

In Xamarin Forms, with native control embedding, you can put native controls (i.e. native Android or iOS controls) on your Xamarin Forms pages. It’s very simple and the official Xamarin Forms documentation (link here) explains how to achieve it. Here’s an example of using native embedding in XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
        xmlns:androidWidget="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
        xmlns:androidLocal="clr-namespace:MyApp.Droid;assembly=MyApp.Droid;targetPlatform=Android"
        x:Class="MyApp.MyContentPage">     
        …
       <ios:UILabel Text="Hello World" TextColor="{x:Static ios:UIColor.Red}" View.HorizontalOptions="Start" />
       <androidWidget:TextView Text="Hello World" x:Arguments="{x:Static androidLocal:MainActivity.Instance}" />
        …
</ContentPage>

At runtime, depending on the platform (iOS or Android), only the native control of that platform is rendered. The other one is just ignored, nothing is created for it. So if we’re running our app on Android, the iOS UILabel declaration in XAML is going to be ignored. The label is just an example, it doesn’t justify embedding the native label since you can just use Xamarin.Forms Label instead.

While it’s not ideal to use separate native controls and not have a single Xamarin Forms control, embedding of native controls is a powerful feature which gives a quick way to add a control you need when Xamarin Forms doesn’t have one for it.

Limitation: no XAML compilation for the Page containing the embedded native control

There’s an important limitation with embedding native controls in XAML: the Xamarin.Forms pages which use XAML and contain embedded native control are skipped for XAML compilation (see here):



XAML compilation is the process run by the Xamarin Forms XAML tooling at build time. It parses the XAML and emits IL code for it, somewhat similar to the code you’d write yourself if you created the same UI by C# code, without XAML. For example, if you use bindings for some controls on the Page, the XAML compilation emits code creating an instance of Binding and setting up the binding. Without XAML compilation, the XAML file is first parsed at run time by the framework in order to figure out what are the controls on the Page which need to ne instantiated. The process of parsing the XAML (which is an XML) at runtime is noticeably slower than just running the IL emitted by the XAML compilation tool at build time.

You’ve might been wondering, why does the native control embedding in XAML works for the page only when XAML compilation is disabled, but not with XAML compilation? I assume this is related to the process of emitting the IL code for the embedded native controls when using XAML compilation, and I hope it’s something it can change in the future.

The very simple workaround

Not having XAML compilation for the whole Page where we embed native controls is not an option. The performance of displaying the page is affected, sometimes significantly, it depends on how many controls the page has.

But the workaround is very simple: move the embedded native view (iOS UILabel and Android TextView) in the example above) to a ContentView (MyContentView) using XAML:

<ContentPage …>     
        …
       <myControls:MyContentView/>
        …
</ContentPage>

<ContentView  … x:Class="MyApp.Views.MyContentView">
       <ios:UILabel Text="Hello World" TextColor="{x:Static ios:UIColor.Red}" View.HorizontalOptions="Start" />
       <androidWidget:TextView Text="Hello World" x:Arguments="{x:Static androidLocal:MainActivity.Instance}" />
</ContentView>

While the XAML compilation does not work for the content of the MyContentView, it works for the page containing the MyContentView, because the page doesn’t directly contain the embeded native view.

The con of this is it requires having an additional view (MyContentView) which otherwise it wouldn't be needed, but the impact is insignificant, especially compared to not using XAML compilation for the whole page. Also, I don't think anybody has too many embedded native control on the same page. A further optimization would be to enable the layout compression on MyContentView but I haven't tested it and I don't think it makes any important difference in this case.

If you found this article interesting and you’d like to hear me write about a specific thing, feel free to reach me out on Twitter.

Comments

Popular posts from this blog

IconFont2Code, my open-source tool in order to view icons in font files and create C# class with the glyph constants

Problems

Xamarin.Forms XmlnsDefinition attribute: All of your namespaces become one