CustomControlsBlazorMobile-870x220

Blazor Mobile Bindings is exciting, but also encourages reusability. We take a look as how to wrap custom Xamarin.Forms UI as Blazor components.

Blazor is one of the most exciting technologies for web developers on the .NET stack and allows for building client/server-side web apps entirely in C#. Blazor is inviting developers into an rich ecosystem and seeing continuous innovations with tooling/performance. Blazor isn't just for web apps though and has clear implications for desktop/mobile.

While experimental, Blazor Mobile Bindings is piquing the interest of many mobile developers, towards building native mobile apps using C#/.NET to target iOS, Android and other platforms. The lure is simple—use Razor syntax and the familiar Blazor component model towards building mobile apps. But what if you are already invested in the Xamarin stack? Maybe you already have Xamarin.Forms apps that you now want to invite Blazor developers into? Perhaps you have existing Xamarin.Forms UI for iOS/Android—would you have to throw everything out and start from scratch?

Thankfully not. Let's take a look at how to expose custom Xamarin.Forms UI, with all functionality, into Blazor components. Developers can have the comforts of using Blazor syntax, while reusing existing custom controls as wrappers.

Why Wrappers

Real progress is often made when we stand on the shoulder of giants. Xamarin.Forms was and continues to be an excellent technology stack, allowing .NET developers to build truly native cross-platform mobile apps. Most .NET developers find it productive to be able to write C#/XAML and have Xamarin.Forms render corresponding native UI on iOS, Android, Mac OS, Tizen and more. Sure, every technology stack has weaknesses and developer tooling can always improve. But it is undeniable how far Xamarin.Forms has matured as a technology stack, boasting a rich ecosystem and a passionate developer community.

Xamarin.Forms does, however, favor .NET developers who are well-versed in using XAML or declarative C# towards building visual trees. Otherwise, and as is the case with .NET web developers, Xamarin.Forms does require a bit of a steep learning curve for developer productivity. ASP.NET web developers are clearly excited about Blazor, and it is perhaps an opportune time to invite web developers to come build native mobile apps. And why reinvent the wheel when Xamarin.Forms already knows how to do the heavy lifting?

With Blazor Mobile Bindings, the goal is to benefit from the expertise of the veteran and sit right on top of the Xamarin.Forms technology stack. Developers would be able to write UI markup/code in Razor syntax and Blazor component model, both familiar to .NET web developers. A little sprinkle of magic and the Blazor UI gets translated to Xamarin.Forms UI under the covers, before rendering native UI on various platforms. This magic is in the form of simple wrappers—code that translates Xamarin.Forms UI into more friendly Blazor code.

Bubble Up the Goodness

So, what does it take to expose a Xamarin.Forms UI control as a wrapper to Blazor markup? Turns out, we need to bubble up two things about each UI component—pertinent properties and event handlers. This ensures that developers using the UI component from a .razor file using Blazor syntax have access to the same goodness as XAML/C# counterparts.

This wrapping of Xamarin.Forms controls into Blazor-land is achieved by implementing two types of classes:

  1. A Component should derive from NativeControlComponentBase.
  2. An element handler representing the UI component that implements the IXamarinFormsElementHandler interface.

Gift Wrap for Custom UI

Most of the default Xamarin.Forms UI components are being wrapped as Blazor components using the same basic princples. The Blazor Mobile Bindings GitHub repo also has an example of wrapping the popular PancakeView Xamarin.Forms component as Blazor UI. But could developers pull this off with custom Xamarin.Forms components? Let's try with a couple of Xamarin.Forms controls from the Telerik UI for Xamarin suite—in particular, the popular NumericInput and Calendar controls.

The first step would be to new up a fresh project using the Blazor Mobile Bindings CLI tool and pull in Telerik UI for Xamarin through the NuGet package. The dependencies of the project are as below. All the code to be written is in the shared .NET Standard library—nothing platform specific.

Nugets  

Here's our _Imports.razor code—nothing out of ordinary here. Notice that we do NOT pull in Telerik namespaces. Many of the Telerik Xamarin.Forms UI come with built-in wrappers—the goal is to do it manually!

@using Microsoft.MobileBlazorBindings
@using Microsoft.MobileBlazorBindings.Elements
@using Xamarin.Essentials
@using Xamarin.Forms

In App.cs, nothing different about app startup either—HelloWorld is the only Blazor component and it is loaded up inside the MainPage, like so:

namespace TelerikBlazorMobile
{
    public class App : Application
    {
        public App()
        {
            var host = MobileBlazorBindingsHost.CreateDefaultBuilder()
                .ConfigureServices((hostContext, services) =>
                {

                })
                .Build();

            MainPage = new ContentPage();
            host.AddComponent<HelloWorld>(parent: MainPage);
        }
        ...
        ...
    }
}

Now, let us write the two pieces of code needed to wrap a Xamarin.Forms Telerik UI control as a Blazor component. The basic code shown here is for NumericInput—the one for the Calendar is identical. First up, we grab the control namespace and register the renderer of the Xamarin.Forms control with the ElementHandlerRegistry, like below. Notice the Step property being exposed for the Blazor component—this would be used to map a property from Xamarin land to Blazor land.

using System;
using Microsoft.MobileBlazorBindings.Core;
using Microsoft.AspNetCore.Components;
using Microsoft.MobileBlazorBindings.Elements;
using Telerik.XamarinForms.Input;

namespace TelerikBlazorMobile
{
    public class RadNumericInput : View
    {
        static RadNumericInput()
        {
            ElementHandlerRegistry.RegisterElementHandler<RadNumericInput>(renderer => new RadNumericInputHandler(renderer, new Telerik.XamarinForms.Input.RadNumericInput()));
        }

        [Parameter] public int Step { get; set; }

        protected override void RenderAttributes(AttributesBuilder builder)
        {
            base.RenderAttributes(builder);
            builder.AddAttribute(nameof(Step), Step);
        }
    }
}

Next up, we wire up the underlying Step property of the NumericInput renderer to the corresponding Step property of the Blazor component, like below. This same technique is to be used to expose to the Blazor component, every underlying property/event handler as desired from the Xamarin.Forms control.

using System;
using Microsoft.MobileBlazorBindings.Core;
using Microsoft.MobileBlazorBindings.Elements;
using Microsoft.MobileBlazorBindings.Elements.Handlers;

namespace TelerikBlazorMobile
{
    public class RadNumericInputHandler : ViewHandler
    {
        public RadNumericInputHandler(NativeComponentRenderer renderer, Telerik.XamarinForms.Input.RadNumericInput numericUI) : base(renderer, numericUI)
        {
            NumericUI = numericUI ?? throw new ArgumentNullException(nameof(numericUI));
        }

        public Telerik.XamarinForms.Input.RadNumericInput NumericUI { get; }

        public override void ApplyAttribute(ulong attributeEventHandlerId, string attributeName, object attributeValue, string attributeEventUpdatesAttributeName)
        {
            switch (attributeName)
            {
                case nameof(Telerik.XamarinForms.Input.RadNumericInput.Step):
                    NumericUI.Step = AttributeHelper.GetInt(attributeValue);
                    break;
                default:
                    base.ApplyAttribute(attributeEventHandlerId, attributeName, attributeValue, attributeEventUpdatesAttributeName);
                    break;
            }
        }
    }
}

That's all. With the two Telerik Xamarin.Forms UI controls wired up as Blazor components and key properties exposed, it's time to try things out. Back in our HelloWorld Blazor component, we can refer to the wrapper components by name and write them as Razor syntax. Notice how the Step property off the NumerInput is being set in classic Blazor code—this indicates the stepping increment/decrement value, like so:

<ContentView>
<StyleSheet Resource="MyStyles.css" Assembly="GetType().Assembly"></StyleSheet>
<StackLayout Margin="new Thickness(30)">

    <Label Text="Hello, World!"
           FontSize="30" />

    <RadCalendar />
    <RadNumericInput Step=@stepper />

</StackLayout>
</ContentView>

@code
{
    int stepper = 20;
}

With fingers crossed, it's time to fire up the mobile simulator and voila!

TelerikControls

And sure enough with the NumericInput control, the up/down stepper jumps by 20 as desired by the parameter passed into the Blazor component. The Blazor component property is mapped correctly down to the corresponding property of the underlying Xamarin.Forms UI—we can set it from 'web' code.

TelerikControlsInAction

Ready Out of the Box

As it turns out, making Blazor component wrappers for custom Xamarin.Forms UI controls is not all that difficult. But, it sure is tedious. Envision UI controls with a ton of properties and event handlers—each one needs to wired up to Blazor counterparts by hand. Wouldn't it be nice if such Blazor wrappers came ready out of the box? Telerik UI for Xamarin can help. Several popular and heavy-hitting Xamarin.Forms Telerik UI now come pre-built with Blazor component wrappers, as seen in the list below. Simply grab the Telerik UI for Xamarin Blazor Nuget package and you would be able to write Blazor code to render Xamarin.Forms UI—all necessary UI properties/event handlers are already wired up.

TelerikBlazorBindings
 

For many developers, seeing is believing. For Telerik UI for Xamarin, there is a sample app called SDK Browser—this is a Xamarin.Forms app that shows developer-focused examples of how to use the UI in various scenarios. Check out the same app now written completely differently—every bit of Xamarin.Forms UI rendered as Blazor components.

SDKBrowser

Wrapping custom Xamarin.Forms UI as Blazor components? Turns out, you do not need to hand-code everything. The Blazor Mobile Bindings GitHub repo has a handy ComponentWrapperGenerator—this is meant to automate much of the process. The goal is to iterate over UI component properties and wrap them for Blazor syntax. No tool is perfect, but this is a great starting point.

Conclusion

Blazor is understandably exciting for .NET web developers, but also has nice implications for desktop/mobile. While experimental, Blazor Mobile Bindings is piquing the interest of many mobile developers. Mobile Blazor Bindings enable developers to build native or hybrid mobile apps using C#/.NET to target iOS, Android and other platforms.

Xamarin.Forms has long been an elegant way to write C#/XAML towards building truly native cross-platforms apps. And for native apps with Blazor, Blazor Mobile Bindings sits right on top of the Xamarin.Forms technology stack. Most custom UI controls written for Xamarin.Forms can be fairly easily wrapped up and exposed as a Blazor component. This has the clear benefit of reusability and being able to use an UI component from Blazor just as one would with Xamarin.Forms. The same exact UI can be rendered either way, thus leading to developer flexibility. Until Blazor Mobile Bindings is production ready, mobile and desktop developers can experiment and rejoice in the possibilities.


SamBasu
About the Author

Sam Basu

Sam Basu is a technologist, author, speaker, Microsoft MVP, gadget-lover and Progress Developer Advocate for Telerik products. With a long developer background, he now spends much of his time advocating modern web/mobile/cloud development platforms on Microsoft/Telerik technology stacks. His spare times call for travel, fast cars, cricket and culinary adventures with the family. You can find him on the internet.

Related Posts

Comments

Comments are disabled in preview mode.