All posts by ÇøŋfuzëÐ SøurcëÇødë

About ÇøŋfuzëÐ SøurcëÇødë

Udara Abhilash Alwis (a.k.a ÇøŋfuzëÐ SøurcëÇødë) Sri Lankan | Geek | Developer | Software Engineer | APIITian | Runner | Cycler |Traveller | Adventurer. Dot net, C#, Java, Xamarin, Windows Phone, Android dev, Inventions, Imaginations, Creativity, and FOSS enthusiast ! ;)

Welcome to my Blazing Pizza Store! ;)

Here’s how I built my Blazing Pizza Store with the awesome .NET Blazor framework… Oh and let me share a quick recap of the awesome knowledge I gained from it!

So recently I embarked on a journey to learn the latest awesomeness of .NET sphere, the Blazor framework, just so that I would be able to leverage some good old C# into the Web and get rid of having to code in JavaScript! :3 lol

Well I just love learning new stuff and building kickass stuff with .NET so obviously I’m loving it! I set up this repository up in my github just to encourage myself to follow up on every possible tutorial and learn of this Blazor awesomeness top to bottom.

Blazor-Playground repo:
UdaraAlwis/Blazor-Playground

That right there is where I’ll be continuously posting of my little self-learning journey into Blazor Framework.

However I came across this lengthy tutorial article through one of my colleagues, published by the .NET Foundation github, called the blazor-workshop!

BlazingPizza, the Blazor Workshop!

So this tutorial features building a Blazor Web Application from ground up for a Online Pizza Ordering shop, called Blazing Pizza! pretty catchy eh! 😉

Before this I had followed up on a few tutorials and video guides for self-learning Blazor bits, but man I gotta tell you this is the most comprehensive tutorial so far…

.NET Foundation, Blazor-workshop repo:
aka.ms/blazorworkshop

It features a step by step guidance on building a complete Blazor Web Application utilizing all the awesomeness it can offer, and it truly elevated my knowledge to another level! Hence I decided to share some of my learning experience with you guys…

Oh and I have published my finished project solution in github as well…

Udara’s Blazing Pizza Store:
UdaraAlwis/Blazor-Playground/BlazingPizzaApp

Published Web App:
https://blazingpizzaappudara.azurewebsites.net/

And I hosted the finished project in Azure as well! 😉

Feel free to try it out! 😀

Prerequisites?!

As for as some pre-requisites, of course you need some basic practice of HTML and CSS, having an idea of how these Web elements comes in together to form web pages and all, would definitely be helpful.

Its better to have a good overall knowledge of .NET programming with C#, as far as the language goes. Even though we’re going to be developing Blazor, it would some advantage if you had previous experience with ASP.NET, as I’ve seen similar elements.

I would not suggest you use this tutorial as your first ever Blazor try out, hence they provide us a pre-set up solution, with the basic Blazor Client UI and Backend API. So it could get confusing or overwhelming to figure it out at once. So its best if you first try out a few simpler demos from Microsoft docs, or a simple follow along Youtube tutorial, there are plenty out there.

Get started with ASP.NET Core Blazor
Build your first Blazor app

Then once you’re familiar with the project solution structure and all, you’re good to go!

Some Tips…

So I started off by copying their starter solution into my own repository, and from there I started following through the steps in the tutorial.

I would read through a given step, understand the objective of it and type the code all by myself. Sometimes I would even try to memorize the syntax and type it on accordingly to the understand I’ve got in that step.

It’s better not to copy paste the code to your own solution directly, I found typing the code by yourself is more effective in the learning curve, so that you get to familiarize with every little detail specially in the syntax.

Take plenty of intervals, for better productivity. This is a long tutorial, but it could be completed in a day, but its best to take some intervals in between to help clear up the exhaustion.

If a certain step is not clear, then you should complete it anyways, then move to the next step, and come back to it later until you get a clear understanding. Some times reading through a given step several times helped me understand better.

Learning journey!

This project BlazingPizza solution is a Blazor Client Side project hosted with ASP.NET, therefore it will be utilizing awesomeness of Web Assembly during the run time on client browser.

Components, Components everywhere!

Component-izing everything is the key in Blazor! Each page should be comprised of Component blocks, which has their own responsibilities separated, increasing the reusability of our code.

Layouts are also built as Components, where you inherit them component from LayoutComponentBase, such as in MainLayout.razor

@inherits LayoutComponentBase

They have a Body parameter where you will be placing the content in.

Dependency Injection!

@inject directive let’s your inject objects into your page that are registered in the DI container, such as,

@page "/"
@inject HttpClient HttpClient

Also you need to make sure those objects are properly registered in the DI, which is located in Program.cs

builder.Services.AddTransient(...);
...
builder.Services.AddScoped(...);

Parameterizing Components…

@code {
    [Parameter] public Pizza Pizza { get; set; }
}

[Parameter] attribute defines a parameters of a Component

Handle HTML Events..

You can specify which HTML event you want to handle using the corresponding HTML attribute in that and then specify the C# delegate you want called..

<li 
    @onclick="@(() => Console.WriteLine(special.Name))" .... >
</li>

Two way binding…

@bind directive lets you two-way bind a value between C# and HTML elements, also with @bind:event you can specify which element triggers the value change as follows…

<input type="range" min="@Pizza.MinimumSize" 
max="@Pizza.MaximumSize" step="1" 
@bind="Pizza.Size" @bind:event="oninput" />

Here we bind the value of <input> element to Pizza.Size, but it will change the value on the oninput event.

Component Event Handling!

You can define Events in a Component by creating EventCallback properties. Then Parent Component can subscribe to those events of a Child Component.

[Parameter] 
public EventCallback OnCancel { get; set; }

Then this Child Component’s elements can trigger it,

<button class="btn btn-secondary mr-auto" 
@onclick="OnCancel">Cancel</button>

And parents who are subscribed can get notified on up on it.

<ConfigurePizzaDialog Pizza="configuringPizza" 
OnCancel="CancelConfigurePizzaDialog" />

CancelConfigurePizzaDialog will be pointing to a method in C#.

Url Parameters into Components!

You can pass parameters into Components from the routing Url, as you see here in the @page directive we define the route along with the [Parameter] with the same name.

@page "/myorders/{orderId:int}"

@code {
    [Parameter] public int OrderId { get; set; }
}

Other parameter types such as string, bool, datetime and guid are supported.

Force Update UI!

Forcefully re-render a component by calling StateHasChanged() method which is built in function in Blazor.

This is handy when you don’t know exactly if the data has changed but wants to make sure its reflected in the UI.

Programmatic Navigation..

NavigationManager allows you to programmatically Navigate in your Blazor app.

@inject NavigationManager NavigationManager
...
...
NavigationManager.NavigateTo($"myorders/{newOrderId}");

AppState pattern…

Save the state of an object in the DI container,

builder.Services.AddScoped<OrderState>();

Saving the state will help you retain data during page navigation across components.

Data Validation!

Using Annotations on the data model you can easily implement Server side data validation. You can start by adding DataAnnotations validation rules onto the model classes.

public class Address
{
	public int Id { get; set; }

	[Required, MaxLength(100)]
	public string Name { get; set; }
	
	[Required(ErrorMessage = "Yo we need for sure!"), MaxLength(50)]
	public string City { get; set; }

	...	
}

This will be picked up by [ApiController] endpoints for validation in Server side.

Then for Client side validation, using EditForm component you can easily implement form validation in Blazor.

<div class="main">
    <EditForm Model="OrderState.Order.DeliveryAddress"  OnValidSubmit="PlaceOrder">
        
		... 

        <button class="checkout-button btn btn-warning" @onclick="PlaceOrder">
            Place order
        </button>
		
		<DataAnnotationsValidator />
		<ValidationSummary />
    </EditForm>
</div>

The above ValidationSummary, displays a basic list of errors, if you need something nicer then its better to decorate those <input> data fields with ValidationMessage instead.

<div class="form-field">
    <label>Name:</label>
    <div>
        <input @bind="Address.Name" />
        <ValidationMessage For="@(() => Address.Name)" />
    </div>
</div>

For better UX use Blazor built in components, such as InputText, InputCheckbox, InputDate, InputSelect, etc…

<div class="form-field">
    <label>Name:</label>
    <div>
        <InputText @bind-Value="Address.Name" />
        <ValidationMessage For="@(() => Address.Name)" />
    </div>
</div>

Authorization!

For enforcing Authorization in Server side, add the [Authorize] attribute on the API Controllers, which is provided by Microsoft.AspNetCore.Authorization namespace.

[Route("orders")]
[ApiController]
[Authorize]
public class OrdersController : Controller
{
    ...
}

This will make sure all incoming calls should be Authorized.

For the Client side we use AuthenticationStateProvider, which is provided by Microsoft.AspNetCore.Components.WebAssembly.Authentication package. Then to enable the authentication services for your Blazor Client, add a call to AddApiAuthorization in Program.cs

public static async Task Main(string[] args)
{
    ....
    // Add auth services
    builder.Services.AddApiAuthorization();
    ...
}

RemoteAuthenticatorView component orchestrates the authentication flow in the Blazor Client app. So to enable this make sure to add the Authentication.razor component.

@page "/authentication/{action}"

<RemoteAuthenticatorView Action="@Action" />

@code{
    [Parameter]
    public string Action { get; set; }
}

It handles all authentication actions such as register, login, profile, and logout.

We need to maintain the Auth state across the client app and inherit into child components, so let’s use CascadingAuthenticationState that wraps the Router of app.razor

<CascadingAuthenticationState>
    <Router AppAssembly="typeof(Program).Assembly" Context="routeData">
        ...
    </Router>
</CascadingAuthenticationState>

AuthorizeView will let you control displaying of elements based on the Auth state.

<AuthorizeView>
	<Authorizing>
		...
	</Authorizing>
	<Authorized>
		...
	</Authorized>
	<NotAuthorized>
		...
	</NotAuthorized>
</AuthorizeView>

Use the IAccessTokenProvider injected to the pages for acquiring an AccessTokens whenever you need to call the API.

var tokenResult = await TokenProvider.RequestAccessToken();
if (tokenResult.TryGetToken(out var accessToken))
{
	...
}
else
{
	NavigationManager.NavigateTo(tokenResult.RedirectUrl);
}

AuthenticationStateTask lets you check programmatically if the user is logged in or not. You can use it as a [CascadingParameter] in any page, thanks to the CascadingAuthenticationState that we added earlier.

[CascadingParameter] 
public Task<AuthenticationState> AuthenticationStateTask { get; set; }

Use it to access User.Identity.IsAuthenticated for checking the User’s Auth state.

protected override async Task OnInitializedAsync()
{
	var authState = await AuthenticationStateTask;
	if (!authState.User.Identity.IsAuthenticated)
	{
		NavigationManager.NavigateTo("authentication/login?redirectUri=/checkout", true);
	}
}

AuthorizeRouteView controls the direct access to routes based on Auth state

<CascadingAuthenticationState>
    <Router AppAssembly="typeof(Program).Assembly" Context="routeData">
        <Found>
            <AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)">
                <NotAuthorized>
                    ...
                </NotAuthorized>
                <Authorizing>
                    ...
                </Authorizing>
            </AuthorizeRouteView>
        </Found>
        <NotFound>
            ...
        </NotFound>
    </Router>
</CascadingAuthenticationState>

You will lose state during redirection, specially in authentication flow, but you can preserve it by implementing RemoteAuthenticationState.

public class PizzaAuthenticationState : RemoteAuthenticationState
{
    public Order Order { get; set; }
}

You need to register it in the DI Services with AddApiAuthorization<PizzaAuthenticationState>() and update the Authentication.razor accordingly by replace the RemoteAuthenticatorView with RemoteAuthenticatorViewCore set up.

@page "/authentication/{action}"

<RemoteAuthenticatorViewCore TAuthenticationState="PizzaAuthenticationState"
    AuthenticationState="RemoteAuthenticationState"
    OnLogInSucceeded="RestorePizza"
    Action="@Action" />

@code{
    ...

    public PizzaAuthenticationState RemoteAuthenticationState { get; set; } = new PizzaAuthenticationState();

    ...
}

You can use the LogOutSucceeded in Authentication component to set the page to redirect to once the user logs out.

builder.Services.AddApiAuthorization<PizzaAuthenticationState>(options =>
{
    options.AuthenticationPaths.LogOutSucceededPath = "";
});

Javascript Interop!

Use IJSRuntime to invoke JavaScript functions from C# code.

await JSRuntime.InvokeVoidAsync
("javascript.functionname", param1, param2);

var result = await JSRuntime.InvokeAsync<bool>
("javascript.functionname", param1);

You can call void methods and even await for results as shown above.

Templated Components…

Using Razor Class Library you can create your own components library for your project solution.

Templated Components can be defined as those components that accepts body content as a parameter. You can create these to increase the reusability and build truly decoupled components.

Use a parameter of type RenderFragment which is a delegate type that the runtime has special handling for, to place content inside a Templated Component.

[Parameter] 
public RenderFragment ChildContent { get; set; }

You can also add multiple RederFragment parameters in a component. We can create a generic-typed component using the @typeparam directive, to support any type of data as follows, @typeparam TItem

[Parameter] 
public RenderFragment Loading { get; set; }
[Parameter] 
public RenderFragment<TItem> Item { get; set; }

and you can set the type and pass parameter content to the generic template by,

<div class="main">
    <TemplatedList TItem="OrderWithStatus" Loader="@LoadOrders">
        <Loading>Loading...</Loading>
        <Item Context="item">
            Status: @item.StatusText
        </Item>
    </TemplatedList>
</div>

PWA bits!

Easily set up PWA features (installable, offline, push notifications) for Blazor, with service-worker.js configuration.

Simply create a service-worker.js file in your Blazor Client’s wwwroot directory, and add the ‘install’ and ‘fetch’ event listeners inside. Then to enable it add a reference of it to the index.html file, beneath the other script elements..

<script>navigator.serviceWorker.register('service-worker.js');</script>

To make your Web app installable, add the manifest.json file in wwwroot directory, which will include app set up details. Then add the reference of it inside the <head> element in index.html

<link rel="manifest" href="manifest.json" />

Setting up Push Notification, first execute the Push Notification permission request from the user through JS script and acquire the NotificationSubscription object, which will provide you the following object filled with Url, P256dh and Auth properties.

You will be passing it over to the API endpoint to save it in the DB with the UserId attached in it. Then when you need to send push notification to your User from your API backend, retrieve the NotificationSubscription object from the DB and use WebPush to execute the broadcast.

var payload = JsonSerializer.Serialize(new
{
	message,
	url = $"myorders/{order.OrderId}",
});
await webPushClient.SendNotificationAsync(pushSubscription, payload, vapidDetails);

Then to display that push notification you need to set up ‘push’ event listener in your service-worker.js and additionally to handle the user click on notification, you can set up ‘notificationclick’ event listener in there as well.

self.addEventListener('push', event => {
...

self.addEventListener('notificationclick', event => {
...

You can generate your cryptographic keys for the push notification set up at https://tools.reactpwa.com/vapid and make sure to update the publicKey in both client and server, then privateKey in server along with the subject, mailto:bingo@bingomail.bingo

Publish to Azure!

To Publish to Azure, you need to create an App Service and a Hosting Plan of Basic tier or higher. Right click on Blazor Server project node -> Publish and follow through the wizard to create your Publish profile.

Before deploying you need to set up a signing key with Azure Key Vault for the IdentityServer. So create a new Key Vault -> create new Certificate (copy the Subject value for later use) -> go to your App Service -> TLS/SSL Settings -> Private Key Certificates (.pfx) -> Import Key Vault Certificate -> Select the imported certificate and copy its thumbprint -> go to Configuration in same App Service -> Add the new key WEBSITE_LOAD_CERTIFICATES and use the thumbprint as the value -> Ok

Then update the BlazingPizza.Server appsettings.json with the Certificate Subject name you configured, “Name”: “CN=BlazingPizzaCertificateUdara”

Publish the App! you’re all done! 😉

It’s go time!

So at the end of all that awesome learning experience, I had built myself a beautiful Blazing Pizza Store web app! 😀

Woot! woot!

Update to the Tutorial…

By the time I almost finished writing this post, they seemed to have updated the tutorial a little bit for the better, such as using the BaseAddressAuthorizationMessageHandler for acquiring access tokens and moving the whole logic to a separate OrdersClient, which will increase the reusability of the code for sure! 😀

Conclusion!

This BlazingPizza workshop tutorial was one of the most comprehensive step by step guide I ever followed for learning Blazor given my last few weeks into this awesome journey. I’m not much of a Web dev fella given my extensive Mobile dev background, but I gotta say I picked up a lot about .NET Web development bits in this tutorial, not only that a complete picture of the awesomeness of Blazor framework.

I hope my humble effort of sharing the new knowledge I gained in Blazor development helps out any fellow devs out there striving to learn new stuff!

Share the love! 😀 Cheers yol!

Restructuring the Xamarin.Forms Shell Default App Template…

Let’s restructure the default project Template for Xamarin.Forms Shell Apps provided by Visual Studio 2019, clean it up, optimize it for the best use of Shell features. 😉

To be more detailed when you create a fresh Xamarin.Forms Shell app, in Visual Studio 2019, you get a certain default template app project provided by VS2019, let me show you how to restructure it in a clean and optimized manner for best use of features, performance and code structure.

Xamarin.Forms Shell is Awesome…

but I had quite a bit confusion understand the reason behind it and the bells and whistles of it, let me explain! So I’ve been working extensively with Xamarin framework for over 4 years now, and I’m confident to say that I have expertized myself on the best use of it. 😀

The way Xamarin.Forms Shell was marketed for was to provide a better alternative for dealing with Master Detailed or Tab Page based Xamarin.Forms Apps. This really made sense to me, since I knew how troublesome or the complexity we have to deal with in those scenarios.

Template Project mess?!

I went through the documentation, followed up on some demo code the community had shared, and once I was confident, it was time to get my hands dirty. So I created a fresh new Xamarin.Forms Shell project in Visual Studio 2019, and started going through the code.

It was a messy chaos! Since the first line of code, it was confusing, with many different Xamairn.Forms implementation practices all over the place in both UI and C# code behind, Xamarin.Forms Classic and Shell navigation mixed up in all over the project and so on. Took me quite a while to get a hold of it. 😦

This is quite a bad set up for a Template project, could be very disorienting for anyone who’s fresh starting off with Xamarin.Forms Shell, let alone Xamarin.Forms itself.

But why?

My best bet is that they wanted to give the perception to the developer that you can interchange and mix up as you like, Xamarin.Forms Classic bits and Shell bits. This is probably in a good intention, but for anyone who’s just starting to grasp it, could be very confusing, mixing up everything together in a template project.

Sure Xamarin.Forms Classic and Shell are completely interchangeable elements, but for a template, you need to give a clear, straight forward way to get started for anyone.

Ze Solution!

So my solution, is to adopt only Xamarin.Forms Shell related implementation, features, and practices into the default Template, so it gives a clear, easy to understand, straight forward view of using Xamairn.Forms Shell to build apps. Thinking in terms of simplest terms, decoupled components with clean and readable code, we need to reflect the best practices of Xamarin.Forms in the Template. 😉

So here I am sharing my journey of restructuring the default project Template for Xamarin.Forms Shell Apps step by step… Also I would like to share this as a guide to fixing up an existing messy project, with all the good coding practices in mind when it comes to Xamarin.Forms! 😀

Default Template Project…

Let’s take a proper look at the what you get fresh out of the box when you create a new Xamarin.Forms Shell project in VS2019 as of now,

So as you can see it promotes MVVM structure in the project, with Models, Views, and ViewModels separated, while also having a separate DataStore service. The basic functionality of this app is to Write text note items with a Title and Description and save them in the memory.

The app consists of ItemsPage where it shows all the text notes added, then ItemDetailsPage where you can view each of the notes, then the NewItemPage which is a modal page allowing you to add new text items, finally a simple AboutPage with a little intro to the Xamarin.Forms Shell.

Issues need Fixes…

Now let me walk you through some of the main problematic bits I found in this template project, one by one…

BindingContext init() inconsistent…

The BindingContext initialization with the ViewModel instance it all over the place, while some pages having it in code behind in the constructor.

And others having it in the XAML itself as shown below..

This should be unified either to code behind Constructor or the other only.

NewItemsPage, no ViewModel!?

For the NewItemsPage, there’s no ViewModel available, and it sets the BindingContext to itself as shown below…

This needs to be modified with its own ViewModel class, and move these data functions into it.

Missing Shell  Query Parameters…

The recommended way to pass data between pages in Xamarin.Forms Shell is to use Query Parameter strings, but this is not reflected in the Template project at all. As you can see below, it uses a tightly coupled Constructor parameter object passing instead.

This needs to be changed to use Xamarin.Forms Shell query parameters, as recommended.

Need to unify Color Resources…

Apart from the global Colors and Styles resources defined in the App.xaml, there are page level resources added as well in some pages.

This should be removed and switched to use global context Colors for better re-usability and reduce repetition of code.

Classic Xamarin.Forms Navigation!? Why!?

Now this was a serious WHY? moment I had when I first saw this, no where in the template project is using actual Xamarin.Forms Shell Route based navigation.

All over the project you will see the Classic Xamarin.Forms Navigation being used.

This needs to be changed to use the actual Shell Route based navigation.

To make it worse, for Modal pages, it implements a very bad practice of forcefully pushing the Navigation Bar on top of it. 😮

Now you can see why I have complained it’s a messy mix of everything, which needs cleaning up with a proper project structure.

Let the Restructuring begin!

Let me walk yol through the whole restructuring process I did step by step, so that you get a clear idea how to make changes in your own projects. Also have pushed this up in my Github repo, if you’re interested in taking a peak.

hosted on github:
github.com/UdaraAlwis/XFShellTemplateDemoApp

Alright then let’s on ahead…

Step 1: Cleaning up Colors and Styles…

Let’s get rid of the page level Color values and move them to the App.xaml, allowing them to be shared on an app global context, increasing re-usability and removing redundancy.

<!--
	Application Styles and Resources
-->
<Application.Resources>
	<ResourceDictionary>
		<Color x:Key="Primary">#2196F3</Color>
		<Color x:Key="Accent">#96d1ff</Color>
		<Color x:Key="LightTextColor">#999999</Color>
	</ResourceDictionary>
</Application.Resources>

Make sure to keep one key for each color value, and share that in all the required elements. Now we have a much cleaner XAML! 😉

Step 2: BaseViewModel to Infrastructure!

The BaseViewModel.cs class is not actively being instantiated but provides a base for the ViewModels of the project, so it would make sense to move out the BaseViewModel.cs class into a separate folder called, Infrastructure.

Also let’s do a bit of code refactoring inside the BaseViewModel, with the field naming, such as private fields, by adding _fieldName format as a good C# code standard.

Step 3: BindingContext in the Constructor()

Let’s have the ViewModel instantiation and its assigning to the Page.BindingContext, inside the Constructor() of each page. Yep, and don’t forget to remove the XAML set up added in the default template. 😉

public partial class ItemsPage : ContentPage
{
    private readonly ItemsViewModel _viewModel;

    public ItemsPage()
    {
        InitializeComponent();

        BindingContext = _viewModel = new ItemsViewModel();
    }
    
    ...
}

This would give better control over the ViewModel’s object instance. The private field will be named accordingly with the “_” prefix, and kept as a private readonly field, since its only going to be instantiated once in the Constructor itself. Make sure to propagate the same for all the Pages in the project.

Step 4: Clean up ItemDetailViewModel!

We need to clean up the ItemDetailViewModel, to be stand-alone and loosely coupled. This will also help us in implementing a proper Shell Route based navigation later.

Let’s convert the Item property into a full fledged property with a private backing field, GETter and SETter. 😉 In the constructor, get rid of the parameter passed in, and let’s assign a dummy value to it as default value.

public class ItemDetailViewModel : BaseViewModel
{
	private Item _item;

	public Item Item
	{
		get => _item;
		private set
		{
			SetProperty(ref _item, value);
			Title = _item?.Text;
		}
	}

	public Command LoadItemCommand { get; set; }

	public ItemDetailViewModel()
	{
		var item = new Item
		{       
                        Id = Guid.NewGuid().ToString(),
			Text = "Sample Item",
			Description = "This is an item description."
		};

		Item = item;

		LoadItemCommand = new Command<string>(async (itemId) => await LoadItem(itemId));
	}

	private async Task LoadItem(string itemId)
	{
		Item = await DataStore.GetItemAsync(itemId);
	}
}

Apart from the Item property, I have added a new Command, which will load the Item details object from the DataStore service.

Now that a well structured, clean ViewModel eh! Next let’s handle the parameter that we’re suppose to pass from ItemsPage to ItemDetailPage…

Step 5: Setting up Query Parameters…

As a part of the previous step, we need to handle the selected Item object that’s being passed into the ItemDetailPage. We’re going to handle this properly with Xamarin.Forms Shell Query parameters. So let’s pass the Id value of the selected Item object, as a query parameter into the page as follows, with the QueryProperty attribute.

[QueryProperty(nameof(ItemId), "itemid")]
public partial class ItemDetailPage : ContentPage
{
	private readonly ItemDetailViewModel _viewModel;
	private string _itemId;

	public string ItemId
	{
		get => _itemId;
		set => _itemId = Uri.UnescapeDataString(value);
	}
	
	...
}

Here we’re maintaining ItemId string property in the Page, where Shell we set the query value into during the navigation.

Do not forget to fire up the LoadItemCommand in the ViewModel of the page, with the ItemId that we acquired during navigation.

...
public partial class ItemDetailPage : ContentPage
{	
	...	
	protected override void OnAppearing()
	{
		base.OnAppearing();

		_viewModel.LoadItemCommand.Execute(ItemId);
	}
}

Alright, then let’s fix the navigation bits next…

Step 6: Use proper Shell Navigation!

Instead of using Xamarin.Forms Classic navigation, let’s migrate all the Navigation bits to proper Xamarin.Forms Shell Route based Navigation yeah!

Let’s start by registering the Page routes, that we use for navigation. Preferably using lower case letters for all the routes.

public partial class AppShell : Xamarin.Forms.Shell
{
	public AppShell()
	{
		InitializeComponent();

		Routing.RegisterRoute("itemdetailpage", typeof(ItemDetailPage));
		Routing.RegisterRoute("newitempage", typeof(NewItemPage));
	}
}

Then update all the navigation bits to use Shell route based navigation…

...
public partial class ItemsPage : ContentPage
{    
    ...
    private async void OnItemSelected(object sender, SelectedItemChangedEventArgs args)
    {
        ...

        await Shell.Current.
                    GoToAsync($"/itemdetailpage?itemid={item.Id.ToString()}");
        ...
    }
}

Now, that’s a proper Shell Navigation in action!

Step 7: Set up NewItemViewModel!

NewItemPage does not have a ViewModel created against it, in order to maintain a proper MVVM structure we need to move all the code behind bits in NewItemPage.xaml.cs into the NewItemViewModel as follows…

public class NewItemViewModel : BaseViewModel
{
    private Item _item;

    public Item Item
    {
        get => _item;
        set
        {
            SetProperty(ref _item, value);
        }
    }

    public NewItemViewModel()
    {
        var item = new Item
        {
           ...
        };

        Item = item;
    }
}

The in the page constructor we assign the instance of this ViewModel to the BindingContext, and you’re done..

Step 8: Use proper Modal Navigation!

The NewItemPage is treated as a Modal page, we should use Shell.PresentationMode instead of classic Navigation.PushModalAsync() for navigating to Modal pages.

First of all make sure we’re navigating to the NewItemPage properly using Shell Route navigation as follows,

...
public partial class ItemsPage : ContentPage
{    
    ...
    private async void AddItem_Clicked(object sender, EventArgs e)
    {
        await Shell.Current.GoToAsync($"/newitempage");
    }
}

Next we set up Shell.PresentationMode property in the NewItemPage to render the page navigation as the Modal page we expect it to be, using ModalAnimated value.

<ContentPage
    x:Class="XFShellTemplateDemoApp.Views.NewItemPage"
    xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
    ios:Page.UseSafeArea="true"
    Shell.PresentationMode="ModalAnimated">

	<!--  Content of the Page  -->
	
	... 

</ContentPage>

Also we should set up the UseSafeArea property for iOS to ignore the iPhone notch, since Modal page overlays the whole app window.

Finally, let’s get rid of the NavigationBar based buttons and use Page Content based Buttons, and modify the UI layout accordingly.

<ContentPage
    x:Class="XFShellTemplateDemoApp.Views.NewItemPage"
    Shell.PresentationMode="ModalAnimated">

    <ContentPage.Content>
        <Grid Margin="0" Padding="0">

            ...

            <StackLayout Padding="15" Orientation="Horizontal">
                <Button
                    BackgroundColor="{StaticResource Primary}"
                    Clicked="Cancel_Clicked"
                    HorizontalOptions="FillAndExpand"
                    Text="Cancel"
                    TextColor="White" />
                <Button
                    BackgroundColor="{StaticResource Primary}"
                    Clicked="Save_Clicked"
                    HorizontalOptions="FillAndExpand"
                    Text="Save"
                    TextColor="White" />
            </StackLayout>

            ...

        </Grid>
    </ContentPage.Content>
</ContentPage>

I have created separate Cancel and Save Buttons which is inside a StackLayout, which in return is inside in the parent Grid Layout where rest of the content resides.

...
public partial class NewItemPage : ContentPage
{    
    ...
    private async void Cancel_Clicked(object sender, EventArgs e)
    {
        await Shell.Current.Navigation.PopModalAsync();
    }
}

For dismissing the page we can stick to PopModalAsync() call in the Navigation stack, since Shell doesn’t have it’s own for that.

Step 9: Overall code quality clean up…

Apart from all these structural changes, another aspect I heavily focused on was, the readability of the code and maintaining proper coding standards, down to the variable naming.

It’s important to properly write the code with all these little details in mind so that its easy to read and understandable by anyone who try to understand the code.

Alright then, with that I conclude the restructuring!

Restructured Template Project…

Aaand let’s take a proper look at what we got at the end after the extensive restructuring of the Xamarin.Forms Shell Template project in VS2019,

Here’s it in action in iOS!

in Android!

Once again you may find the whole project code is hosted on my Github repo,

hosted on github:
github.com/UdaraAlwis/XFShellTemplateDemoApp

Feel free to fork it out and use it as anyway you wish, may be even for a starter pack for your Xamarin.Forms Shell App development journey! 😉

Conclusion!

Well that concludes my journey of restructuring the Xamarin.Forms Shell default project template in VS2019, for the best use of Shell features, performance and optimized clean code.

Xamarin.Forms Shell is actually an awesome new paradigm to build Xamarin.Forms app, but honestly the VS2019 Template project could really use some proper restructuring for making it easier and straight forward for the beginners to start off. 😉

Share the love! 😀 Cheers yol!

Publishing the Nuget of my Color Picker Control for Xamarin.Forms!

Let me share the journey of me publishing the Nuget Package of my interactive Color Picker Control for Xamarin.Forms that I built using SkiaSharp.

So some time back I built an Interactive and responsive Color Picker Control for Xamarin.Forms (Android, iOS, UWP) with a whole bunch of awesome features. On a Canvas with a beautiful Color spectrum similar to a rainbow gradient effect spreading across, drag, drop, swipe and pan over the Canvas to pick the Color you need easily, in a fun-to-use interactive experience. Built from pure Xamarin.Forms based on SkiaSharp, lightweight and fast!

Backstory…

In my previous blog post I shared with you guys how I built my interactive Color Picker Control for Xamarin.Forms, https://theconfuzedsourcecode.wordpress.com/2020/02/26/i-built-an-interactive-color-picker-control-for-xamarin-forms/

Since then I had been adding a whole bunch of extra feature to this Color Picker Control I built, so I thought it was a good idea to publish it as a Nuget Package and share with everyone! 😀

So this time, let me share my journey of implementing more advanced features and publishing the Nuget Package of my Color Picker Control for Xamarin.Forms! 😉

Some thought…

So before I isolated my Color Picker Control into a stand alone reusable package, I wanted to make sure that I maintain my philosophy of building Plugins. This would definitely have a big impact on your Users who will will be using these Plugins to build their apps, therefore I’ll share the tick list that I consider as important as follows…

Plug and Play: The plugin should easy to set up with. Do not force Devs to set up any dependencies or property values by themselves. The properties and behaviors of the Plugin should have default values assigned to them.

Customization: It should be easy and straight forward for the Devs to customize the appearance or the behaviors of the Plugin. In some case this might be limited, but you must build the Plugin in a way it make it easy as much as possible.

Embedded: In the case of UI Element Plugins, you should make it easy to be embedded into any Layout structure, being able to inherit the Parent Layout’s behaviors and values, without overriding or disrupting them.

Keep it Light: Make the Plugin as lightweight as possible, give the Dev the chance to choose which assemblies to be included in the plugin. Remove unnecessary references or dependencies from your Plugin core, so it’s light weight as possible.

Performance First: It shouldn’t cause any performance bottleneck, therefore from scratch you must build the Plugin with performance in mind. Constantly check for performance improvements during the development of your Plugin.

So may be go over this list before you build or release a Plugin for the public! 😉 Alright, with all those principles in mind, let’s move ahead…

The Features!

So here are the features that are already available in the Color Picker Control that I built which I had shared from my previous blog post…

  • Picked Color: The Property that allows Users to retrieve the Color values that’s selected from the Color Picker. This value is only a Get Property.
  • Picked Color Changed Event: The Event that fires up every time the PickedColor Value is changed during Color selection. You can subscribe to this event and observe the behavior.

Since my venture into this Color Picker Plugin I had a few ideas in mind as improvements or rather add as extra features, rather than just being a UI Element which allows you to pick a color on a beautiful spectrum! 😉 So here are the extra features that I’ll be building up into it..

  • Change the Available Base Colors List: You can set the primary list of Colors where the gradient spectrum will be rendered from. So choose the base colors you want to be populated as you wish and it will be rendered on the Color Picker.
  • Change the Color List Flow Direction: You will be able to change the direction of the flow of the colors on the canvas, where it be Horizontal flow or a Vertical flow of the color spectrum. Further more Horizontally being starting off the flow from left to right, and Vertically being top to bottom.
  • Change the Color Spectrum Style: You will be able to change the style of the Color Spectrum gradient, the rendering combination of base colors (Hue), or lighter colors (Tint) or darker colors (Shade). You’ll be able to set it with different order as well, ex: Hue Colors, Shade Colors, Tint Colors or Tint Colors, Hue Colors, Shade Colors, etc..
  • Change the Appearance of the Pointer: The white color circle that is used as the Picker Pointer on the Canvas, should be able to customized based on its Diameter or Thickness of the Circle border. Another nice addition would be to allow user to set the position of the Pointer as they wish.

Alright, now that we listed down the new intended feature set that I’m planning to ship out with my Color Picker Control, let’s get down to building it… 😀

Sneak Peak!

Just to give a little glimpse of the awesomeness I ended up building and publishing… 😀 behold the Color Picker Control for Xamarin.Forms!

Pretty awesome eh! 😉 I have moved out of my previous repo to a new standalone repo in github, since I’m publishing this as a package. Therefore all the new development will be done in this repository.

Project hosted on github:
https://github.com/UdaraAlwis/XFColorPickerControl

So feel free to take a look in there before we continue… 😉

Time to Build!

Since I already explained in my previous blog post how I built my Color Picker Control from scratch step by step, I won’t be repeatedly going through same code bits in this post, but rather focus on the new changes and features only.
If you haven’t read that one yet, then I would recommend you take a peak there first, I built an Interactive Color Picker Control for Xamarin.Forms! And continue here…

I named the Solution as Udara.Plugin.XFColorPickerControl, and in return I intend to keep the Package reference with the same naming. I am using Visual Studio 2019 on Windows 10 here as my development environment.

I have created a VS Solution with a .NET Standard 2.0 Library which will hold the UI Control in place, with the naming ColorPicker. You can see I have added the dependencies of the Plugin, with Xamarin.Forms and SkiaSharp.Views.Forms packages. 😉

Notice the pure Xamarin.Forms DemoApp project inside the Demo folder that I have added to the same solution? That is for testing and showcasing the Plugin’s use, also as a reference point for anyone who wants to learn how to use the Plugin in many different ways, this attached DemoApp could come handy. 😀

The ColorPicker.xaml is the UI Element that users will be using under the namespace Udara.Plugin.XFColorPickerControl.ColorPicker in their XAML or C# code for building the UI. Here’s base skeleton implementation of the ColorPicker.xaml.cs, which all the core implementation will be taking place…

namespace Udara.Plugin.XFColorPickerControl
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class ColorPicker : ContentView
    {
        public ColorPicker()
        {
            InitializeComponent();
        }

        // Implementation goes here
    }
}

Next let’s get into the implementation of Features one by one as I discussed before…

Building the Features!

So I’m going to use the same code for the two features that I already implemented in my previous blog post, Picked Color and Picked Color Changed Event feature that’s represented by PickedColor Property and PickedColorChanged Event Handler.

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ColorPicker : ContentView
{
	/// <summary>
	/// Occurs when the Picked Color changes
	/// </summary>
	public event EventHandler<Color> PickedColorChanged;

	public static readonly BindableProperty PickedColorProperty
		= BindableProperty.Create(
			nameof(PickedColor),
			typeof(Color),
			typeof(ColorPicker));

	/// <summary>
	/// Get the current Picked Color
	/// </summary>
	public Color PickedColor
	{
		get { return (Color)GetValue(PickedColorProperty); }
		private set { SetValue(PickedColorProperty, value); }
	}
	
	...
}

Now considering the rest of the features that I discussed in the beginning, all those features can be implemented and exposed via Bendable Properties, and handling the Property Changed events internally to react for any changes requested during run time.

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ColorPicker : ContentView
{
    ...
 
    public static readonly BindableProperty PropertyNameProperty
        = BindableProperty.Create( 
        ... 
        
            validateValue: (bindable, value) =>
            {
                // validate value
                return (..);
            },
            
            propertyChanged: (bindable, value, newValue) =>
            {
                if (newValue != null)
                    // action on value change
                else
                    // handling null values
                    ((ColorPicker)bindable).PropertyNameProperty = default;
            });
        );
 
    public type PropertyName
    { ... }
 
    ...
}

All the Bindable Properties are safeguarded with validations as you see above. I have added an extra layer of protection against unnecessary null values being set up, by defaulting the property value to default of itself. You can check the full implementation of each of these Properties on the github repo itself. github.com/UdaraAlwis/XFColorPickerControl Let’s begin..

Feature: BaseColorList

Bindable Property, BaseColorList: Change the available base Colors on the Color Spectrum, of the Color Picker. This will take a List of strings of Color names or Hex values, which is held in an IEnumerable as show here, also I have set up the fallback default values with the rainbow color spectrum.

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ColorPicker : ContentView
{
    ...

    public static readonly BindableProperty BaseColorListProperty
        = BindableProperty.Create( ... );

    public IEnumerable BaseColorList
    { ... }

    ...
}

This Property is then consumed during the SkiaSharp rendering cycle as follows, where as we’re using the Xamarin.Forms built in ColorTypeConverter to parse the string color values to actual Color objects and then to SKColor objects, which is then used to render the render the color spectrum on the Color Picker Control. 😀

...
    private void SkCanvasView_OnPaintSurface
                   (object sender, SKPaintSurfaceEventArgs  e)
    {
        ...
         
        // Draw gradient rainbow Color spectrum
        using (var paint = new SKPaint())
        {
            paint.IsAntialias = true;
 
            // Initiate the base Color list
            ColorTypeConverter converter = new ColorTypeConverter();
            System.Collections.Generic.List<SKColor> colors = 
                new System.Collections.Generic.List<SKColor>();
            foreach (var color in BaseColorList)
                colors.Add(((Color)converter.
		          ConvertFromInvariantString(color.ToString())).ToSKColor());
				
            ...
        }
    }
...

Pretty straight forward eh! Let’s see how you could use this as a developer.

How to use?

You can easily use this feature in XAML as follows, by accessing ColorPicker.BaseColorList property and setting up the list of color values you prefer as hex values or with pre-defined color value names.

<xfColorPickerControl:ColorPicker
	x:Name="ColorPicker"
	...	>
	<xfColorPickerControl:ColorPicker.BaseColorList>
		<x:Array Type="{x:Type x:String}">
			<!--  Yellow  -->
			<x:String>#ffff00</x:String>
			<!--  Aqua  -->
			<x:String>#00ffff</x:String>
			<!--  Fuchsia  -->
			<x:String>#ff00ff</x:String>
			<!--  Yellow  -->
			<x:String>#ffff00</x:String>
		</x:Array>
	</xfColorPickerControl:ColorPicker.BaseColorList>
</xfColorPickerControl:ColorPicker>

If you prefer in C# code, you can easily do as as well, a list of string values of the colors…

ColorPicker.BaseColorList = new List<string>()
{
	"#00bfff",
	"#0040ff",
	"#8000ff",
	"#ff00ff",
	"#ff0000",
};

Here’s some action…

Feature: ColorFlowDirection

The Bindable Property, ColorFlowDirection: Change the direction in which the Colors are flowing through on the Color Spectrum, of the Color Picker. This will allow you to set whether the Colors are flowing through from left to right, Horizontally or top to bottom, Vertically. I have defined an Enum type which will represent this type of course.

namespace Udara.Plugin.XFColorPickerControl
{
    public enum ColorFlowDirection
    {
        Horizontal,
        Vertical
    }
}

Let’s create our ColorFlowDirection Bindable Property based on that,

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ColorPicker : ContentView
{
    ...

    public static readonly BindableProperty ColorFlowDirectionProperty
        = BindableProperty.Create( ... );

    public ColorFlowDirection ColorFlowDirection
    { ... }

    ...
}

The default value will be set as ColorFlowDirection.Horizontal, and if the User changes value during run time, it will fire up a new SkiaSharp rendering cycle of the Canvas, effectively rendering the spectrum accordingly to the new color value, which is handled in the rendering logic as below…

...
    private void SkCanvasView_OnPaintSurface
                   (object sender, SKPaintSurfaceEventArgs  e)
    {
        ...
        
            // create the gradient shader between base Colors
            using (var shader = SKShader.CreateLinearGradient(
                new SKPoint(0, 0),
                ColorFlowDirection == ColorFlowDirection.Horizontal ?
                    new SKPoint(skCanvasWidth, 0) : 
                    new SKPoint(0, skCanvasHeight),
                colors.ToArray(),
                null,
                SKShaderTileMode.Clamp))
            {
                paint.Shader = shader;
                skCanvas.DrawPaint(paint);
            }
            
        ...
    }
...

The trick here is to configure the SKShader.CreateLinearGradient() method’s start and end coordinate parameters, which governs the direction in which the gradient effect will be drawn with the list of colors, thus rendering the color list from left to right or top to bottom. As you can see for Horizontal effect, we use SKPoint (0,0) to SKPoint(<canvasWidth>, 0) by using the corner most value on the X axis for the end coordinates, the same pattern is used for Vertical effect with bottom most value on the Y axis.

Here how to consume this feature as a developer…

How to use?

You can easily use this feature in XAML, by accessing ColorPicker.ColorFlowDirection property and setting Horizontal or Vertical option as you prefer…

<xfColorPickerControl:ColorPicker
	x:Name="ColorPicker"
	ColorFlowDirection="Horizontal"
	...	>
</xfColorPickerControl:ColorPicker>

If you prefer in C# code, use the ColorFlowDirection.Horizontal or Vertical option…

ColorPicker.ColorFlowDirection =
	Udara.Plugin.XFColorPickerControl.ColorFlowDirection.Horizontal;

Here’s some action…

Feature: ColorSpectrumStyle

The Bindable Property, ColorSpectrumStyle: Change the Color Spectrum gradient style, with the rendering combination of base colors (Hue), or lighter colors (Tint) or darker colors (Shade). If you’re not familiar with these technical terms, here’s a clear illustration of comparison of Hue, Shade, and Tint of Colors.

We need to make sure our Color Picker is able to deliver to this kind of requirement, having darker or lighter colors of the given base colors on the Color Picker Spectrum. So I’ve created an Enum type which will consist of all the possible combinations of Hue, Shade and Tint colors based on the available Base Colors, that would facilitate this feature.

namespace Udara.Plugin.XFColorPickerControl
{
    public enum ColorSpectrumStyle
    {
        HueOnlyStyle,
        HueToShadeStyle,
        ShadeToHueStyle,
        HueToTintStyle,
        TintToHueStyle,
        TintToHueToShadeStyle,
        ShadeToHueToTintStyle
    }
}

Let’s create our ColorSpectrumStyle Bindable Property based on that,

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ColorPicker : ContentView
{
    ...

    public static readonly BindableProperty ColorSpectrumStyleProperty
        = BindableProperty.Create( ... );

    public ColorSpectrumStyle ColorSpectrumStyle
    { ... }

    ...
}

I will be setting ColorSpectrumStyle.HueToShadeStyle as the default value for this property, any changes to this value during run time will kick start a new refresh draw on the Color Spectrum, which is handled in the rendering logic as below…

...
    private void SkCanvasView_OnPaintSurface
                   (object sender, SKPaintSurfaceEventArgs  e)
    {
        ...
         
        // Draw secondary gradient color spectrum
        using (var paint = new SKPaint())
        {
            paint.IsAntialias = true;
 
            // Initiate gradient color spectrum style layer
            var colors = GetSecondaryLayerColors(ColorSpectrumStyle);
			
            ...
        }
    }
...

Over here, we’re retrieving the list of colors based on the ColorSpectrumStyle value, which is a combination of Transparent, Black and White colors, which will be used to draw the secondary gradient layer. GetSecondaryLayerColors() will be returning the appropriate list of secondary colors that matches the ColorSpectrumStyle requested as follows.

...
    private SKColor[] GetSecondaryLayerColors(ColorSpectrumStyle colorSpectrumStyle)
    {
        ...
        
        if (colorSpectrumStyle == GradientColorStyle.DarkToColorsToLightStyle)
        {
            return new SKColor[]
            {
                SKColors.Black,
                SKColors.Transparent,
                SKColors.White
            };
        }
        
        ...
    }
...

I’m maintaining a simple If-else block chain which will check for the ColorSpectrumStyle value available and return the appropriate list of colors back. Quite straight forward! 😉

Now here’s how you use this awesome feature…

How to use?

You can easily use this feature in XAML, by accessing ColorPicker.ColorSpectrumStyle property and setting the appropriate Style option as you prefer…

<xfColorPickerControl:ColorPicker
	x:Name="ColorPicker"
	ColorSpectrumStyle="TintToHueToShadeStyle"
	...	>
</xfColorPickerControl:ColorPicker>

If you prefer in C# code…

ColorPicker.ColorSpectrumStyle =
	Udara.Plugin.XFColorPickerControl.ColorSpectrumStyle.TintToHueToShadeStyle;

Here’s some action…

Feature: PointerRing Styling

As you can see there’s a pretty neat Pointer Ring that’s pointing the picked color position on the Color Picker, it would be nice to be able to customized this too eh! 😉

Therefore I have introduced four features for this,

  • PointerRingDiameterUnits
  • PointerRingBorderUnits
  • PointerRingPositionXUnits
  • PointerRingPositionYUnits

Alright, let’s walk through them one by one..

Feature: PointerRingDiameterUnits

The Bindable Property, PointerRingDiameter: Changes the Diameter size of the Pointer Ring on the Color Picker. It accepts values between 0 and 1, as a representation of numerical units which is compared to the 1/10th of the longest length of the Color Picker Canvas. By default this value is set to 0.6 units.

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ColorPicker : ContentView
{
    ...
 
    public static readonly BindableProperty PointerRingDiameterUnitsProperty
        = BindableProperty.Create( ... );
 
    public double PointerRingDiameterUnits
    { ... }
    
    ...
}

This will be calculated against the longest length of Color Picker’s Canvas, whether it be Width or Height. The reason for adding another 1/10th of the value is to maintain the maximum size of the Pointer Ring, avoiding ridiculous sizing of the element. lol So the Precise calculation is as, Canvas Size (Height or Width) x PointerRingDiameterUnits x (1/10)
This value will render exactly to the same proportion against different screen sizes and DPs.

...
    private void SkCanvasView_OnPaintSurface
                   (object sender, SKPaintSurfaceEventArgs  e)
    {
        ...
         
        // Painting the Touch point
        using (var paint = new SKPaint())
        {
            ...
 
            var canvasLongestLength = (skCanvasWidth > skCanvasHeight) 
                    ? skCanvasWidth : skCanvasHeight;

            // Calculate 1/10th of the units value for scaling
            var pointerRingDiameterUnitsScaled = (float)PointerRingDiameterUnits / 10f;
            // Calculate against Longest Length of Canvas 
            var pointerRingDiameter = (float)canvasLongestLength 
                                                    * pointerRingDiameterUnitsScaled;

            // Outer circle of the Pointer (Ring)
            skCanvas.DrawCircle(
                _lastTouchPoint.X,
                _lastTouchPoint.Y,
                (pointerRingDiameter / 2), paintTouchPoint);

            ...
        }
    }
...

I’ve set up the skCanvas.DrawCircle() with the (pointerRingDiameter / 2) since it accepts radius value only for drawing the circle.

How to use?

You can easily use this feature in XAML, by accessing ColorPicker.PointerRingDiameterUnits property and setting the value against your Color Picker’s Width and Height.

<xfColorPickerControl:ColorPicker
    x:Name="ColorPicker"
    PointerRingDiameterUnits="0.6"
    ...    >
</xfColorPickerControl:ColorPicker>

If you prefer in C# code…

ColorPicker.PointerRingDiameterUnits = 0.6;

Here’s some action…

Feature: PointerRingBorderUnits

The Bindable Property, PointerRingBorderUnits: Changes the Border Thickness size of the Pointer Ring on the Color Picker. It accepts values between 0 and 1, as a representation of numerical units which is calculated against the diameter of the Pointer Ring. By default this value is set to 0.3 units.

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ColorPicker : ContentView
{
    ...
 
    public static readonly BindableProperty PointerRingBorderUnitsProperty
        = BindableProperty.Create( ... );
 
    public double PointerRingBorderUnits
    { ... }
    
    ...
}

This calculation executes against the Pointer Ring’s pixel diameter value as, (Pointer Ring Diameter in Pixels) x PointerRingBorderUnits, since this is dependent on the Pointer Ring’s diameter, we thickens the border inside that circle only. Basic technique here is to draw a Circle inside the Parent Circle, with the picked pixel point’s color, emulating the visual of a Ring.

...
    private void SkCanvasView_OnPaintSurface
                   (object sender, SKPaintSurfaceEventArgs  e)
    {
        ...
         
        // Painting the Touch point
        using (var paint = new SKPaint())
        {
            ...
 
            // Draw inner circle with picked color
            paintTouchPoint.Color = touchPointColor;

            // Calculate against Pointer Circle
            var pointerRingInnerCircleDiameter 
                          = (float)pointerRingDiameter 
                              * (float)PointerRingBorderUnits; 

            // Inner circle of the Pointer (Ring)
            skCanvas.DrawCircle(
                _lastTouchPoint.X,
                _lastTouchPoint.Y,
                ((pointerRingDiameter 
                        - pointerRingInnerCircleDiameter) / 2), paintTouchPoint);
            ...
        }
    }
...

I’ve set up the skCanvas.DrawCircle() with the calculation, ((pointerRingDiameter – pointerRingInnerCircleDiameter) / 2) since it accepts radius value only for drawing the circle.

How to use?

You can easily use this feature in XAML, by accessing ColorPicker.PointerRingBorderUnits property and setting the value against PointerRingDiameterUnits you have used.

<xfColorPickerControl:ColorPicker
    x:Name="ColorPicker"
    PointerRingBorderUnits="0.3"
    ...    >
</xfColorPickerControl:ColorPicker>

If you prefer in C# code…

ColorPicker.PointerRingBorderUnits = 0.3;

Here’s some action…

Feature: PointerRingPosition<X,Y>Units

The Bindable Property, PointerRingPosition<X,Y>Units: Changes the Pointer Ring’s position on the Color Picker Canvas programmatically. There are of two bindable properties PointerRingPositionXUnits and PointerRingPositionYUnits, which represents X and Y coordinates on the Color Picker Canvas. It accepts values between 0 and 1, as a presentation of numerical units which is calculated against the Color Picker Canvas’s actual pixel Width and Height. By default both the values are set to 0.5 units, which positions the Pointer Ring in the center of the Color Picker.

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ColorPicker : ContentView
{
    ...
 
    public static readonly BindableProperty PointerRingPositionXUnitsProperty
        = BindableProperty.Create( ... );
 
    public double PointerRingPositionXUnits
    { ... }
	
    public static readonly BindableProperty PointerRingPositionYUnitsProperty
        = BindableProperty.Create( ... );
 
    public double PointerRingPositionYUnits
    { ... }
 
    ...
}

This calculation executes against the Color Picker Canvas’s actual pixel Width and Height as, (Color Picker Canvas Width in Pixels) x PointerRingPositionXUnits and (Color Picker Canvas Height in Pixels) x PointerRingPositionYUnits
Up on invoke of the PropertyChanged on those Properties, we make a call to the following SetPointerRingPosition() with the new X and Y position units requested from User.

...
    private void SetPointerRingPosition
                      (double xPositionUnits, double yPositionUnits)
    {
        // Calculate actual X Position
        var xPosition = SkCanvasView.CanvasSize.Width
                                 * xPositionUnits; 
        // Calculate actual Y Position
        var yPosition = SkCanvasView.CanvasSize.Height
                                 * yPositionUnits; 

        // Update as last touch Position on Canvas
        _lastTouchPoint = new SKPoint(Convert.ToSingle(xPosition), Convert.ToSingle(yPosition));
        SkCanvasView.InvalidateSurface();
    }
...

We’re calculating the actual X and Y coordinates against the Canvas pixel size and setting up the _lastTouchPoint with those values, for keeping the Pointer Ring position on canvas in sync with touch inputs positioning and programmatical positioning, then at the end we fire up the SkiaSharp rendering cycle with SkCanvasView.InvalidateSurface();

Handling Pointer Ring Position on Initialization!

We need to handle the positioning of the Pointer Ring on the initialisation or on the rendering of the element during run time. We can achieve this by a one-time execution with a boolean flag, that executes this logic. So upon the first SkiaSharp canvas rendering cycle, we hook up to the PointerRingPositionXUnits and PointerRingPositionYUnits properties and render the Pointer Ring Position to the set value.

...    
    private bool _checkPointerInitPositionDone = false;

...
    private void SkCanvasView_OnPaintSurface
                   (object sender, SKPaintSurfaceEventArgs  e)
    {
        ...
          
        if (!_checkPointerInitPositionDone)
        {
            var x = ((float)skCanvasWidth * (float)PointerRingPositionXUnits);
            var y = ((float)skCanvasHeight * (float)PointerRingPositionYUnits);

            _lastTouchPoint = new SKPoint(x, y);

            _checkPointerInitPositionDone = true;
        }
    }
...

We use _lastTouchPoint variable which is used by the drawing functions for rendering the Pointer Ring on Color Picker’s Canvas.

How to use?

You can easily use this feature in XAML, by accessing ColorPicker.PointerRingPositionXUnits property and ColorPicker.PointerRingPositionYUnits setting the values against your Color Picker’s Width and Height.

<xfColorPickerControl:ColorPicker
    x:Name="ColorPicker"
    PointerRingPositionXUnits="0.3"
    PointerRingPositionYUnits="0.7"
    ...    >
</xfColorPickerControl:ColorPicker>

If you prefer in C# code…

ColorPicker.PointerRingPositionXUnits = 0.3;
ColorPicker.PointerRingPositionYUnits = 0.7;

Here’s some action…

UWP Bug Fix!

One issue I noticed was on UWP run time, where the SkiaSharp’s Canvas touch event behaves differently than iOS and Android. The touch event would get activated even if you hover over the canvas using your mouse pointer, and this was causing the PickedColor property to fire up.
The Touch event should occur only if you actually click on the canvas and drag and drop on the Canvas, so in order to fix this I used the InContact property SKTouchEventArgs inside the touch event to validate on UWP run time.

...
    private void SkCanvasView_OnTouch
                (object sender, SKTouchEventArgs e)
    {
        // to fix the UWP touch behavior
        if (Device.RuntimePlatform == Device.UWP)
        {
            // avoid mouse over touch events
            if (!e.InContact)
                return;
        }

        _lastTouchPoint = e.Location;
        
        ...
    }
...

This fixed the bug on UWP, making sure the touch event is validated before executing the rest of the logic.

Nugetizing!

Alright then, its time to set up our beautiful Color Picker Control for Xamarin.Forms as a Nuget Package using Visual Studio. I’m going first set the Nuget package properties first, then build the package, and finally publish it to Nuget, allowing it to be shared with everyone out there! 😀

Set up package properties…

You could do this straight from Visual Studio Project Properties, or directly from a Nuspec file added to the project itself. For now I would prefer setting up properties in VS Project -> Properties – Package tab, making sure to add all the necessary properties and information about the package as shown below…

Make sure to click on “Generate Nuget package on build” tick, which will enable all the property fields. You could also do this by editing .csproj file of the package project as well, if you require any fine tuned editing…

Now we’re ready to build the package of our Udara.Plugin.XFColorPicker library.

Building the Package…

We need to create the Publish Profile for the package.
Right click on Library project node -> Publish

If this was your first time, it will navigate you to create new Publish Profile tab as shown below…

It is easier to set up a Publish Profile, since you don’t have to manually change your build configuration to Release and then launch a build. Therefore I have set it up now, and next time I publish it will straightaway handle all the configuration for you! 😀

Click Publish, and it nicely builds…

Once we navigate to the folder location mentioned in the above build output…

There we have our nupkg package file, which we can then use to directly upload to Nuget!

Upload to Nuget…

Grab that nupkg file and drag and drop into the upload page of nuget.org and you’re done!

Here you’ll be able to add a short marked down documentation for the users, I would highly recommend you do that since it will increase the support and visibility.

Well that’s all it takes, and the package will be available in a few hours on Nuget!

Updating Package…

Now how do we update our package? if you have noticed around nuget, there’s no update option in in the page where you manage the package. You can update your package by using the NuGet command-line utility or directly uploading an increment build, in which I have opted for the end option to keep it easy.

So when you want to push an update to your package, make sure to update the package properties in Visual Studio to reflect the next immediate version, as shown below where I’m updating from version 1.0.2 to version 1.0.3…

Also do no forget the assembly versioning as well…

Now build your package and directly go to nuget upload page, drag and drop the file…

Make sure to add the nuget documentation and Submit!

Done and dusted, just like that, the updating is done! 😀

Published on nuget:
nuget.org/Udara.Plugin.XFColorPickerControl/

Now anyone can use my Color Picker Control for Xamarin.Forms by setting up this nuget package in their project…

Demoing it up!

As you saw at the beginning I have attached a Demo project into the same parent Solution of Udara.Plugin.XFColorPickerControl, which I have used for testing during development, and to maintain as a demonstration of all the awesome features this plugin provides! 😉

Since this plugin is meant to be compatible on a cross platform environment its impeccable do continuous testing on all the platforms. Anyhow here’s a sneak peek of the demo app…

I have created separate pages to demonstrate awesomeness of each special feature…

BaseColorList Demo:

Android, UWP and iOS…

ColorFlowDirection Demo:

Android, UWP and iOS…

ColorSpectrumStyle Demo:

Android, UWP and iOS…

PointerRingStyling Demo:

Android, UWP and iOS…

Since it’s a pure Xamarin.Forms and can be deployed directly to all three platforms, Android, iOS and Windows UWP, you can do the same with my plugin. Feel free to take a look at the demo app in case if you need trouble shooting.

Conclusion!

There you have it my Color Picker Control for Xamarin.Forms, now published to nuget as a package, with a whole bunch of awesome features, and anyone can easily use it in their own Xamarin.Forms projects! 😀 Pheww… What a joy! Sharing something you’ve been working so hard for a long time. So feel free to give a try, contribute, and any feedback is always welcome…

hosted on github:
github.com/UdaraAlwis/XFColorPickerControl

published on nuget:
nuget.org/Udara.Plugin.XFColorPickerControl/

Well that was fun! So keep in mind I’m going to be implementing more and more features for this plugin in future, and might end up changing some of those features or implementations as well. This blog post will not be constantly updated against them, so many sure to keep in touch with the docs in the github repo itself for future references.

Imagination is the limit yol! 😉

Share the love! 😀 Cheers!

I built an Interactive Color Picker Control for Xamarin.Forms!

Let me share my adventure of building an awesome interactive and responsive Color Picker UI Control for Xamarin.Forms with the help of a little SkiaSharp magic! 😉

To blow your mind, imagine something similar to the Color Picker your have in Ms Paint, HTML Web Color Picker or Google Search Web Color Picker…

Think of how interactive and fun to use those UI Elements are, with their drag and drop pointers on the color spectrum which picks up the color from wherever you drop it.

Why can’t we have the same easy to use fun interactive experience in our Xamarin.Forms apps?

Color Picker control is something that’s missing out of the box in Xamarin.Forms, even when it comes to 3rd party controls out there, neither of them are interactive or responsive, let along any fun to use all. lol 😀

Backstory…

Some time back, I ventured in a project where it required me to build a Color Picking UI element, where it would be easy to use for the user to have a similar experience to what we have with Ms Paint, or Web Color Picker UI elements. So I started off by looking at existing 3rd party library controls out there, which ended up me being disappointed seeing all the controls are just static boring color selection lists of grid style elements.

So I started building my own interactive fun-to-use Color Picker from scratch modeled after the Color Picker UI controls we have in Ms Paint, HTML Web Color Picker, etc… The awesomeness of this would allow you to touch, swipe and pan across a beautiful spectrum of color scheme and pick the color you desire! 😀

So… What?

So what we really need to build in this case is, create a Canvas with a full Color spectrum similar to a rainbow gradient effect spreading across, while allowing the User to touch at any given pixel point, up on which an event will trigger capturing the Color value of that pixel point. Also we should be able to highlight that touch triggered pixel point, giving the feedback to the User.

How? in a Gist…

Frankly this is not possible at all, out of the box in Xamarin.Forms, but with the help of a little SkiaSharp magic, this would be possible! SkiaSharp is the awesome 2D graphics rendering library that let’s you do all kinds of cool stuff on top of Xamarin.Forms. So basically we’re going to draw the full Color spectrum with a rainbow-gradient style spreading across a 2D canvas with the help of SkiaSharp.

We will define the list of main colors we need to include across the Canvas, while defining the Gradient fading effect between them. Then with regards to Touch, we need to enable this on the SkiaSharp canvas, and subscribe to the touch handling events.

Then given the User triggers a touch even on the Canvas, we will pick up those coordinate values on the canvas, and pick the Color values of the Pixel at that point on the Canvas. Voiala! We got the Color value picked by the User! 😉 Then as a responsive feedback we will draw highlighting circle around that pixel point coordinates on the Canvas. 😀

Well there you have it, quite straight forward eh! 😉

Sneak Peak!

Just to give a little sneak peak, here’s what I build… 😀 Behold the Interactive Color Picker Control for Xamarin.Forms!

Pretty awesome eh! Xamarin.Forms + SkiaSharp magic! 😉

Project hosted on github:  
https://github.com/UdaraAlwis/XFColorPickerControl 

Alright then let me show you how I built it…

Let’s start building!

Let’s begin by adding SkiaSharp to our Xamarin.Forms project. Open up Nuget Package Manager on your Xamarin.Forms solution node and add SkiaSharp.View.Forms Nuget to your .NET Standard project node and platform nodes as shown below…

That’s it, no extra set up is needed… 😉

Next we need to create our Custom Control, which I’m going to name as ColorPickerControl!

The ColorPickerControl!

It’s better to keep this in a dedicated folder in the .NET Standard project, inside a “Controls” folder, for the sake of clarity! 😉 So let’s create our ColorPickerControl as a type ContentView XAML element in the Controls folder…

<?xml version="1.0" encoding="utf-8" ?>
<ContentView
    x:Class="XFColorPickerControl.Controls.ColorPickerControl"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:d="http://xamarin.com/schemas/2014/forms/design"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <!-- Content of the Control -->

</ContentView>

Then as of the code behind, let’s set up a PickedColor Property that holds the value of the Color that User picks during the run time, and an event that fires itself up on that action, PickedColorChanged event!

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ColorPickerControl : ContentView
{
	public event EventHandler<Color> PickedColorChanged;

	public static readonly BindableProperty PickedColorProperty
		= BindableProperty.Create(
			nameof(PickedColor),
			typeof(Color),
			typeof(ColorPickerControl));

	public Color PickedColor
	{
		get { return (Color)GetValue(PickedColorProperty); }
		set { SetValue(PickedColorProperty, value); }
	}

	public ColorPickerControl()
	{
		InitializeComponent();
	}
}

Alright next on to setting up the SkiaSharp bits in our Control…

The SkiaSharp magic!

SkiaSharp’s magical Canvas called SKCanvasView is what we’re going to use to Draw our Rainbow Color Spectrum and handle all the Touch event bits… So let’s begin by adding the SKCanvasView to our ColorPickerControl XAML and also the SkiaSharp.Views.Forms reference in the XAML itself..

<ContentView
    ...
    xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
	...
	>

    <skia:SKCanvasView
        x:Name="SkCanvasView"
        EnableTouchEvents="True"
        PaintSurface="SkCanvasView_OnPaintSurface"
        Touch="SkCanvasView_OnTouch" />

</ContentView>

Code on Github: /XFColorPickerControl/Controls/ColorPickerControl.xaml

As you can see on my SKCanvasView element, I have enabled touch events with EnableTouchEvents property and subscribed to Touch event with SkCanvasView_OnTouch. Subscribing to PaintSurface allows us to draw full blown 2D graphics on the Canvas, which is why we have created the event SkCanvasView_OnPaintSurface event.

So let’s handle all those events in the code behind of our ColorPickerControl…

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ColorPickerControl : ContentView
{
	...
	
	private void SkCanvasView_OnPaintSurface
                      (object sender, SKPaintSurfaceEventArgs e)
	{
		var skImageInfo = e.Info;
		var skSurface = e.Surface;
		var skCanvas = skSurface.Canvas;

		var skCanvasWidth = skImageInfo.Width;
		var skCanvasHeight = skImageInfo.Height;

		skCanvas.Clear(SKColors.White);

		...
	}
	
	private void SkCanvasView_OnTouch
                      (object sender, SKTouchEventArgs e)
	{
		...
	}
}

Code on Github: /XFColorPickerControl/Controls/ColorPickerControl.xaml.cs

So we’re setting up the basic values we need to use inside SkCanvasView_OnPaintSurface with the skImageInfo, skSurface, skCanvas, which will be very useful in our next set of code snippets!

This is where our core implementation is going to be taking place, let me get into details of each code snippet one by one, but you can always go back to the full code on github and take a look by yourself… 😉 Let’s continue…

The Touch!

Let me begin diving in with the SkCanvasView_OnTouch event method implementation, which handles the touch events occurs on the SkiaSharp Canvas we added into our Control.

We need to keep a track on each Touch event that occurs, so we will store that in a local variable _lastTouchPoint which is of type SKPoint. Since we need to only consider the touch events that occur inside the canvas region, we’re validating each touch coordinate (X,Y) that comes into the event.

...
	private void SkCanvasView_OnTouch
	               (object sender, SKTouchEventArgs e)
	{
		_lastTouchPoint = e.Location;

		var canvasSize = SkCanvasView.CanvasSize;

		// Check for each touch point XY position to be inside Canvas
		// Ignore any Touch event ocurred outside the Canvas region 
		if ((e.Location.X > 0 && e.Location.X < canvasSize.Width) &&
			(e.Location.Y > 0 && e.Location.Y < canvasSize.Height))
		{
			e.Handled = true;

			// update the Canvas as you wish
			SkCanvasView.InvalidateSurface();
		}
	}
...

Based on the validated touch event coordinate, we’re firing up the SkiaSharp Canvas drawing cycle, SkCanvasView.InvalidateSurface(), where we will handle, picking up the color on the touch point and redrawing the canvas to highlight the touch point coordinates on the Canvas.

The Rainbow Color Spectrum!

So this right here is the most critical functionality that we need to implement, drawing the beautiful rainbow gradient color spectrum on our SkiaSharp Canvas. We’re going to draw the following list of colors across the spectrum, which values I picked up with the help of Google Web Color Picker..

Red | Yellow | Green (Lime) | Aqua | Blue | Fuchsia | Red
undefined

This will take place in our SkCanvasView_OnPaintSurface event method that we created in the previous step, where we create the Paint object that’s going to draw the color spectrum on the Canvas, along with the gradient fading effect between all the colors using SKShader object.

...
	private void SkCanvasView_OnPaintSurface
	               (object sender, SKPaintSurfaceEventArgs  e)
	{
		// Draw gradient rainbow Color spectrum
		using (var paint = new SKPaint())
		{
			paint.IsAntialias = true;

			// Initiate the primary Color list
			// picked up from Google Web Color Picker
			var colors = new SKColor[]
			{
				new SKColor(255, 0, 0), // Red
				new SKColor(255, 255, 0), // Yellow
				new SKColor(0, 255, 0), // Green (Lime)
				new SKColor(0, 255, 255), // Aqua
				new SKColor(0, 0, 255), // Blue
				new SKColor(255, 0, 255), // Fuchsia
				new SKColor(255, 0, 0), // Red
			};

			// create the gradient shader between Colors
			using (var shader = SKShader.CreateLinearGradient(
				new SKPoint(0, 0),
				new SKPoint(skCanvasWidth, 0),
				colors,
				null,
				SKShaderTileMode.Clamp))
			{
				paint.Shader = shader;
				skCanvas.DrawPaint(paint);
			}
		}
	}
...

As you can see we are defining the list of Colors with SKColor objects, that’ll populate the rainbow color spectrum on our Canvas. Then we use SKShader.CreateLinearGradient() method to build the gradient shader using the list of colors, and then we draw it on the Canvas using skCanvas.DrawPaint().

Keep a note how SKPoint() objects define the starting and ending coordinates on the Canvas which the shader will spread through, thus we’re taking skCanvasWidth picking the corner most value on the X axis. 😉

The Darker Gradient Strip!

Next we need to draw the darker shadow gradient strip on the Canvas allowing Users to pick the Darker Colors of the primary colors we defined.

We’re going to paint the darker color regions by drawing another layer on top of the previous drawn layer creating the illusion of darker regions of each color.

This will take place in our SkCanvasView_OnPaintSurface but below the code snippet that I showed before. Very much similar to the previous snippet, we’re doing almost the same thing but adding a darker gradient region at the bottom of the Canvas.

...
	private void SkCanvasView_OnPaintSurface
	               (object sender, SKPaintSurfaceEventArgs  e)
	{
		...
		
		// Draw darker gradient spectrum
		using (var paint = new SKPaint())
		{
			paint.IsAntialias = true;

			// Initiate the darkened primary color list
			var colors = new SKColor[]
			{
				SKColors.Transparent,
				SKColors.Black
			};

			// create the gradient shader 
			using (var shader = SKShader.CreateLinearGradient(
				new SKPoint(0, 0),
				new SKPoint(0, skCanvasHeight),
				colors,
				null,
				SKShaderTileMode.Clamp))
			{
				paint.Shader = shader;
				skCanvas.DrawPaint(paint);
			}
		}
	}
...

Here we’re drawing the darkening gradient layer starting from Transparent color to Black color across the Y axis, thus we’re taking skCanvasHeight picking the corner most value on the Y axis similar to what we did before. 😉

Here they are side by side, before and after drawing darker gradient strip… 😀

The Lighter Gradient Strip!?

This this is bit of an extra cherry on top, as you may have seen some of those Color Pickers include picking Lighter versions of the Colors. We can easily do this by adding a White color object to the list of colors in the code snippet I shared above.

...         
	...
		 ...
			// Initiate the darkened primary color list
			var colors = new SKColor[]
			{
				SKColors.White,
				SKColors.Transparent,
				SKColors.Black
			};  
		 ...
	...
...	

This will draw the secondary layer with White | Transparent | Black gradient effects on top of the full color spectrum layer.

There you go, with the Lighter color gradient strip. Although I wouldn’t include this in my demo app code 😛 Just coz I don’t like it! lol

Picking the Color on Touch!

This is the most crucial bit of this Control, also the most time consuming implementation I had to go through during my trial and error experimentation to get this working! 😮

We are going to be using the _lastTouchPoint SKPoint object, that we created before, in order to access the coordinate data of the touch point on Canvas. Then we look for extract the pixel color values on that coordinate on the Canvas, given that the Canvas is already rendered with the Color spectrum.

This will take place in our SkCanvasView_OnPaintSurface event method, below the color spectrum drawing code snippet.

Experimentation Phase…

Picking a pixel on the rendered Canvas layer is not a straight forward task, the idea here is to capture a quick snapshot of the Canvas graphic layer and convert that into a bitmap image, and use that image to pick the pixels from using the touch coordinates.

As you can see from below, the first implementation I put together which captures a snapshot of the Canvas surface layer and load it into a SKBitmap image, then I retrieve the Pixel data on that image using bitmap.GetPixel() by passing in the touch point values.

...
	private void SkCanvasView_OnPaintSurface
				   (object sender, SKPaintSurfaceEventArgs  e)
	{
		...
		
		// Picking the Pixel Color values on the Touch Point

		// Represent the color of the current Touch point
		SKColor touchPointColor;

		//// Inefficient: causes memory overload errors
		//using (var skImage = skSurface.Snapshot())
		//{
		//	using (var skData = skImage.Encode(SKEncodedImageFormat.Webp, 100))
		//	{
		//		if (skData != null)
		//		{
		//			using (SKBitmap bitmap = SKBitmap.Decode(skData))
		//			{
		//				touchPointColor = bitmap.GetPixel(
		//									(int)_lastTouchPoint.X, (int)_lastTouchPoint.Y);
		//			}
		//		}
		//	}
		//}
		
		...
	}
...

Later it started causing performance issues due to calling Snapshot() method during each rendering cycle, which is a very heavy process, and even sometimes overloads the memory.

Better Solution…

So after a bit more exploration with trial and error, I managed to build a solution based on a Xamarin Forum response that I found to a similar requirement I had…
https://forums.xamarin.com/discussion/92899/read-a-pixel-info-from-a-canvas

What if instead of taking a snapshot, we use SKImageInfo object of the Canvas instance and extract a SKBitmap image and read the pixel color data of the touch point coordinates. This is way more efficient and consumes much less memory for execution… 😉

...
	private void SkCanvasView_OnPaintSurface
				   (object sender, SKPaintSurfaceEventArgs  e)
	{
		...
		
		// Picking the Pixel Color values on the Touch Point

		// Represent the color of the current Touch point
		SKColor touchPointColor;

		// Efficient and fast
		// https://forums.xamarin.com/discussion/92899/read-a-pixel-info-from-a-canvas
		// create the 1x1 bitmap (auto allocates the pixel buffer)
		using (SKBitmap bitmap = new SKBitmap(skImageInfo))
		{
			// get the pixel buffer for the bitmap
			IntPtr dstpixels = bitmap.GetPixels();

			// read the surface into the bitmap
			skSurface.ReadPixels(skImageInfo,
				dstpixels,
				skImageInfo.RowBytes,
				(int)_lastTouchPoint.X, (int)_lastTouchPoint.Y);

			// access the color
			touchPointColor = bitmap.GetPixel(0, 0);
		}
		
		...
	}
...

As you can see we’re using skSurface.ReadPixels() to load the pixel data on the coordinates, and finally loading the exact pixel data into touchPointColor as a SKColor object type. 😀

So now we picked the Color from a given touch point on the Canvas, let’s move to the next bit…

The Touch Feedback!

This is the part where we provide on touch feedback for the User by highlighting the touch point on the Canvas up on each touch event. As you noticed we’re firing up the OnPaintSurface event upon each touch event of the Canvas, hence we can draw the highlighting region on the Canvas right here as a feedback loop.

We’re simply going to create a SKPaint object, with White color and use skCanvas.DrawCircle() to draw a circle around the touch point coordinates on the Canvas. Then as an added extra, I’m drawing another circle on top of it with the picked color, so that we can emphasize on the pixel color of the touch point. 😉

...
	private void SkCanvasView_OnPaintSurface
				   (object sender, SKPaintSurfaceEventArgs  e)
	{
		...
		
		// Painting the Touch point
		using (SKPaint paintTouchPoint = new SKPaint())
		{
			paintTouchPoint.Style = SKPaintStyle.Fill;
			paintTouchPoint.Color = SKColors.White;
			paintTouchPoint.IsAntialias = true;

			// Outer circle (Ring)
			var outerRingRadius = 
				((float)skCanvasWidth/
                    (float)skCanvasHeight) * (float)18;
			skCanvas.DrawCircle(
				_lastTouchPoint.X,
				_lastTouchPoint.Y,
				outerRingRadius, paintTouchPoint);

			// Draw another circle with picked color
			paintTouchPoint.Color = touchPointColor;

			// Outer circle (Ring)
			var innerRingRadius = 
				((float)skCanvasWidth/
                    (float)skCanvasHeight) * (float)12;
			skCanvas.DrawCircle(
				_lastTouchPoint.X,
				_lastTouchPoint.Y,
				innerRingRadius, paintTouchPoint);
		}
		
		...
	}
...

As you can see _lastTouchPoint X and Y coordinates to draw the circle, and we’re calculating the radius value for both circles by adjacent to Canvas width and height, so it renders nicely on any device scale.

And then to the final step, returning back the Color that we Picked from our ColorPickerControl!

Return the Picked Color!

Now we need to return back the Color value that the User picked, to the subscribers or whoever’s listening to the PickedColor property and PickedColorChanged event.

...
	private void SkCanvasView_OnPaintSurface
				   (object sender, SKPaintSurfaceEventArgs  e)
	{
		...
		
		// Set selected color
		PickedColor = touchPointColor.ToFormsColor();
		PickedColorChanged?.Invoke(this, PickedColor);
		
		...
	}
...

It’s as simple as setting the Value and firing up the Event with the new Color value parameter…

Alright, that’s it! We’ve finished building our awesome ColorPickerControl! 😀

Let’s try it out!

Since we created it as a standalone UI Control you can use this little awesomeness anywhere in your Xamarin.Forms project as you would with any UI element as easy as below…

<controls:ColorPickerControl 
	x:Name="ColorPicker"
	PickedColorChanged="ColorPicker_PickedColorChanged" />

So let’s try adding this to a ContentPage with a nice little Frame element around it with a fixed Height and Width…

<Frame
	x:Name="ColorPickerFrame"
	CornerRadius="8"
	HeightRequest="200"
	HorizontalOptions="Center"
	WidthRequest="350">
	<controls:ColorPickerControl 
		x:Name="ColorPicker"
		PickedColorChanged="ColorPicker_PickedColorChanged" />
</Frame>

This will give a nice little frame around the Color picker control, then on to the code behind…

private void ColorPicker_PickedColorChanged
			(object sender, Color colorPicked)
{
	ColorPickerHolderFrame.BackgroundColor = colorPicked;
}

PickedColorChanged provide you the picked Color value, so you can do what you wish with it!

Fire it up!

Time to fire it up yo! 😀 I’ve prepared a little demo app with my awesome ColorPickerControl for Xamarin.Forms, deployed for Android, iOS and UWP…

Android, iOS and UWP side by side working like a charm! 😀

Project hosted on github:  
https://github.com/UdaraAlwis/XFColorPickerControl 

The possibilities are endless, just a matter of your own creativity! 😉

Conclusion…

An interactive and responsive Color Picker is something that’s missing from Xamarin.Forms out of the box, even when it comes existing to 3rd party controls, there’s no such that fills the requirement, similar to MS Paint Color Picker, or HTML Web Color Pickers.

You can do all kinds of cool interactive 2D graphics rendering stuff with SkiaSharp on Xamarin.Forms, and thanks this, I managed to build a full fledged interactive and fun-to-use Color Picker UI Control, which is lacking in Xamarin.Forms ecosystem right now.

I’m planning to release a nuget package with this control quite soon, with a whole bunch of extra cool features embedded in 😉 So keep in touch!

Imagination is the limit yol! 😉

Share the love! 😀 Cheers!

This is how I built SSRS RDL Reports for Microsoft Dynamics 365…

Let me share my journey of building SSRS RDL Reports for Microsoft Dynamics 365 CRM using Visual Studio 2015, with the Report Authoring Extension to pull data through FetchXML queries!

Backstory…

So recently I found myself working on a Dynamics 365 Reporting project module, where I had to build a set of Reports that are to be executed in the cloud on demand. The data for those reports had to be pulled from the Dynamics 365 cloud, using FetchXML queries, process it through a set of business logic and then display to the user in a nice looking Report Layout.

This can be nicely done using a Microsoft SQL Server Reporting Services Project where it will allow you to build the RDL Report files that you need to upload to the Dynamics 365 environment, allowing the reports to be executed directly from there.

So let me share my journey step by step… 😉

The Set up!

In order to pull data from Microsoft Dynamics 365 using FetchXML queries, we need to have Visual Studio 2015 installed with Dynamics 365 Report Authoring Extension installed. This is only set up that’s properly functioning. which I released after a series of trial and error try out!

So here is the set up I used during my journey,

  • Install Visual Studio 2015 Community Edition
  • Install SQL Sever Data Tools (version 17.4)
  • Install Microsoft Dynamics 365 Report Authoring Extension (version 9.0)

I have posted a blog article of the step by step installation of this whole set up previously in detail, so you might want to give it a read before proceeding…

Let's set up Microsoft Dynamics 365 Fetch Extension in VS2015!
https://theconfuzedsourcecode.wordpress.com/2020/02/11/lets-set-up-microsoft-dynamics-365-fetch-extension-in-vs2015/

Now that we have set up the dev tools and environment required, let’s look into the best practices of maintain our SSRS Report Project solution.

Project Structure…

It’s best to maintain a single Project Solution for all your Reports, even if you’ve got multiple types of Reports under different categories or modules, you could maintain them in a tree folder structure.

Each Report must maintain its own Data Source, which all the Datasets will use to execute their Queries to pull data from the Dynamics 365 CRM. I found having a shared Data Sources or a Data Sets some times troublesome between different Reports.

Alright then lets get started by creating the Project Solution for our Reports.

Create the Report Project!

Let’s open up Visual Studio 2015, Create New Project -> Templates -> Business Intelligence -> Reporting Services and select Reporting Server Project as follows…

Once the Project is created then its time to create the Reports…

Create the Report!

In the Report Data view, right click on the Reports folder -> Add New Item -> select Report -> give an appropriate name to your new Report and click Add..

Once the new Report is created, it will open up Report Data View, if not visible on your Visual Studio 2015 solution, go to View -> Report Data or hit the short cut keys, Ctrl + Alt + D on your keyboard! 😉

Add the Data Source!

This is where we define the connectivity to our Microsoft Dynamics 365 CRM, allowing our Datasets to pull data from, to be used in the Reports.

In the Report Data view, Right click on Data Sources -> Add New Data Source -> Set up your Data Source with your Dynamics 365 hosted link with the Credentials as shown below…

Once that’s done, next we need to set up our Datasets…

Adding the Dataset!

You could add multiple Datasets as you wish according to your requirement, which will all be pulling data through the Data Source that you created above.

In the Report Data view, Right click on Datasets -> Add New Dataset

Give an appropriate name to your Dataset, and select the “Use a dataset embedded in my report” option, which will allow you to select the Data Source that you created above.

Insert the FetchXML query that you intend to be executing though this dataset to pull data from Dynamics 365, which will populate the data that you require to populate in the Report at the end. 😀

FetchXML Queries, everywhere!

This is something worth the notice, regarding the FetchXML queries, you need to make sure you build your queries properly, error free, as well as performance in mind. The most complex your Report gets, the more FetchXML queries and datasets that you will have to set up.

One of my colleagues, Lohit introduced the team to this awesome tool called XrmToolBox https://www.xrmtoolbox.com/, that you can use to build your queries. This tool allows you to install plugins in it, specially one specific one, FetchXML Builder plugin. This will allows you to easily build, configure and debug your FetchXML queries, against a Dynamics 365 data source.

It’s got a nice FetchXML query editor with all the functionality available in each keyword, allowing you to execute those queries that you build in real time and see the actual data results, experiment, making it easier to debug, and tweaking performance. So you might wanna So you might wanna give it a try and save time! 😉

Dataset Data Fields!

Once you add the FetchXML Query to your Dataset properties, you need to make sure the query is populating the data accordingly. You can check this by clicking on the Fields tab on the left pane in the window.

This will most likely prompt you to login to Dynamics 365 data source that you created before, once that’s done, and if the FetchXML properly written, then you should see all your Data Fields in this Dataset populated as below…

Or you can even see the dataset fields populated once you save the new dataset, in the Report Data view as follows…

Now we’re ready to design our Report…. 😉

Design the Report Layout!

Make sure you have selected the Design mode of your Report, the top region of the Designer represents the Parameters display area, and the bottom white box is the Report Layout area that we can build our Report UI.

So open up the Toolbox Pane in your Visual Studio, and you will see all the UI Elements available for you to design your RDL Report.

Let’s drag and drop a Textfield element, that will represent the Title of the Report and a Data Table element that will populate the data of the Report as shown below…

Now we can populate data on that Report Layout

Data on Report Layout!

How to attach our Data Fields from the Dataset we created? it’s actually quite easy, just drag and drop the Dataset Fields on to each column of the Data Table element on the designer that we added earlier…

You wanna add more columns, please go ahead right click on the last column -> Insert Column -> Right will do it! 😀

It’s really easy to design the Report Layout and set up the data fields that we want to display!

Report Data Formatting!

One of the most fun things that I encountered was implementing custom data formatting in the Reports that I built. You can easily add all kinds formatting for the data fields with the use of Expressions that’s cooked into SSRS Reports. I’ve written a comprehensive blog post about this, which you can take a look for further learning.

Data formatting in SSRS RDL Reports with Field Expressions…
https://theconfuzedsourcecode.wordpress.com/2020/02/15/data-formatting-in-ssrs-rdl-reports-with-field-expressions/

This will help you format and manipulate the data you get from your datasets to display on the report according to your business logic requirement.

Report Parameters!

You can add data Parameters to your Reports, which will allow you to re-populate the data on the go, for easy analysis of Report results. Check out my comprehensive blog post about this, which will walk you through a step by step guide how to add Parameters to your Reports..

Adding Parameters will include you having to create multiple datasets to populate the data for the Parameters themselves, then based on those Parameter values User selects during execution, Report data will be automatically filtered and repopulated.

Test and Repeat!

You can use the Preview tab in the Report Design view to test your Report, how they would render in Dynamics 365. Although for myself I had trouble testing these reports locally, so each time I had to upload to Dynamics 365 and test it directly from there.

You can also Build the VS project solution locally, to see if everything is set up properly, and no errors are popping out. So make sure to test the Reports locally if possible.

Once you’ve done building your Report in Visual Studio, grab your RDL files from the project solution, and then its time to elevate them up to the Microsoft Dynamics 365 cloud! 😀

Upload Report to Dynamics 365!

Now it’s time to upload our Report to Microsoft Dynamics 365, which is actually quite easy, click and click you’re done! 😉 Just open up your Dynamics 365 endpoint -> go to the Reports section -> click on the New button at the top…

This will bring up the New Report window, where you will have all the options you need to set up your new Report in Dynamics 365. Since we’re uploading a file, in the Report Type, use the Existing File option in the. Then you can click on the Choose file button and attach your RDL Report file.

Make sure to give a proper Name and Description for your Report, although one thing you need to keep in mind is that, you need to make sure to set up the Related Record Types field, where you need to set up all the Entities that you’re pulling in data from for your Report.

This is governed by the FetchXML query that you built to pull data from Dynamics, whatever the linking Entities that you use, you need to mention them in this field as follows…

Once you’ve set up everything in the wizard, click on Save button at the top left corner, and you will see your new Report appeared in the Reports section of your Dynamics 365!

Just click on that Report, and it will open itself up on a new browser tab and execute itself, populating the data like a charm! 😉

Updating Reports in Dynamics 365!

This is actually quite easy and similar to uploading your Report, simply select your Report in the list of Reports available and click Edit button.

This will open up the Report Edit window, where you can upload your New RDL Report file, or edit any other data in your Report set up.

Once you’re done, just Save and exit, your changes will reflect in the Dynamics 365!

Conclusion

You can easily build powerful Reports for Microsoft Dynamics 365 using SQL Server Reporting Tools. You need to use Visual Studio 2015 installed with Dynamics 365 Report Authoring Extension, on top of SQL Server Data tools set up as your dev environment.

Simply put, building your Reports follows these steps…

  • Create the Report
  • Add Dynamics 365 Data Source
  • Add FetchXML Query based Dataset
  • Design Report Layout
  • Add Data Formatting with Expressions
  • Add Parameters for the Report
  • Test your Reports before Publishing

Your FetchXML queries plays a huge role in pulling the data from Dynamics 365, so you need to make sure your queries are properly set up, error free, with perfomance impact in mind. Use a tool like XrmToolbox with FetchXML Builder plugin could make it easier.

Once you’re done with building your Reports, you can directly upload them to Dynamics 365, also make sure to set up details and the data dependency entities of that Report. Editing and Updating those reports are quite the same process as well.

Hope this little step by step guide helped someone, somewhere out there… happy building my fellow devs! 😀

Share the love! 😀 Cheers!

Let’s Parameterize our SSRS RDL Reports!

Let me show you, how to add parameters to SSRS RDL Reports, while populating the reporting data based on those parameters dynamically!

You can add any number and any type of parameters into your Reports, so that during the execution users can easy load different sets of data into the Reports for analysis.

Backstory…

Since my last few posts I’ve been revealing to you guys that I’ve been working with Microsoft Dynamics 365, where I built those Reports using SQL Server Reporting Services RDL Reports, where those RDL files are uploaded to the Dynamics 365, allowing use to execute them directly from there.

In those Reports, I’ve added a bunch of Parameters where they can load different sets of data into the Reports through those reports for different analytics of the data. Yeah sounds pretty cool eh! 😉 So I thought of sharing this experience with you all, how I added the feature of passing Parameters into my RDL Reports for Microsoft Dynamics 365!

the Set up!

So my set up was on Visual Studio 2015 with SSRS in order to build Reports using fetchXML based data sources that pulls data from Microsoft Dynamics 365 cloud, which was a helpless requirement specifically with the Report Authoring Extension. Let’s set up Microsoft Dynamics 365 Fetch Extension in VS2015!

Although I believe the process of adding parameters any SSRS RDL Report is the same, so you should be able to follow along despite your targeted deployment source. 🙂

Parameters for Reports!

So you need to add Parameters for your RDL Report eh, which means you’ll be passing a bunch of data values into the filtering pipeline of the Report and repopulate its results based on it.

So how do we add those Parameters? We need to build each one of those Parameters in our SSRS project. This is where you configure what is the type of the parameter, whether its Text, Date, Boolean, and so on, you can even define your own set of data values available for this parameter, which the user will choose from during execution. It also facilitates you to define the data source in which those values will be loaded from.

Then you add those Parameters into the Report, by adding a dependency between them. Once they are set you need to determine the refresh cycle for re-loading the data based on the new parameters given. 😉

Now as you can see there’s all kinds of cool stuff you can do with it, even though the set up seem a bit complicated, its actually quite straight forward! 😀

We need to get started by defining the Parameters in our Report! So go ahead and open up your RDL Report with Design View…

Let’s get Started!

In order to add any Parameter, you need to first define it in your project, so first make sure you have the “Report Data” View is opened up.

To open up the Report Data View if not visible on your Visual Studio 2015 solution, go to View -> Report Data or hit the short cut keys, Ctrl + Alt + D on your keyboard! 😉

Let’s dive right into it by, Right click on the Parameters -> Add Parameters

This will open up the dialog to create a new Parameter to be added to your Report…

Now this let’s you define your Parameter with the properties you want to set for, starting from the values available in it, to the refresh action up on the user’s selection. As you can see I have here “ReportParameter1” which is labeled as “Report Parameter 1 :” for the display fields in the Report. You can choose the type of data this parameter represents and the type of inputs it accepts from the user.

So let’s go over each section you need to consider when you’re creating a Parameter.

Parameter: Available Values!

This allows you to determine the set of values available for your Parameter, that is presented to the user during execution. You can also leave this in the “None” option which will let the user type in the value they prefer.

If you want to load a specific list of values in to this parameter, then you can select “Specify values”, which will allow you to build the list of data values with their representing label value as shown before. This will provide the user with a drop down list of data using this source.

If you’d like to populate the data for this Parameter using a data query source that you can build, then feel free to select the “Get values from a query” option, in which case the list of data will be loaded from this dataset source based on the query defined in it, and be presented to the user accordingly with the Labeled values.

I will get in to this query based data loading into the Parameter, later in this article 😉

Then the next section you need to consider is the Default Values…

Parameter: Default Values!

This is where you define the default value that’s loaded into your Parameter during the execution, in which case you could also leave it with the “No default value” option selection if you don’t want to have any pre-selected values for loading of the data.

If you select “Specify values” option here, it will allow you to choose the default value to be loaded from the list of data that you defined in the “Available Values” section as I’ve shown before.

Now the same way you could populate your default values based on Expressions as well, in a situation like setting the default value for a Date type parameter can easily be done as below…

But if you’ve defined a data source based on a query, then you can select the data from that source to be loaded here as well from the option “Get values from a query“. You need to make sure to select the same dataset that you selected in “Available Values” section here as well.

Next the final section you need to consider when building your Parameter, “Advanced” section!

Parameter: Advanced!

This is where you define the refresh action based on the selection of a new value for the Parameter from the user during execution. Simply put let report refresh its data every time a user selects a new parameter value, or let the user refresh manually to see the results once change the selection.

Now that’s quite straight forward eh! So those are key sections you need to focus on when building any Parameter for your RDL Report.

Next let’s deep a little more into loading values from query into your Parameter… 😀

Let’s get Values from a Query!

As I’ve shown earlier you can load data into your Parameter from a dataset source based on a query. Let me show you how easy it is to set this up! 😉

Let’s get started by creating the dataset that will handle loading the data from the data source that we target. Right click on the “Datasets” section -> Add Dataset… option.

Create a new dataset using an existing shared dataset, or using an existing data source by accessing the data through the preferred query type.

As you can see below here in my example, I’m using a fetchXML query to be execute through my TestDataSource which is a MS Dynamics 365 data source. So you need to build your own query based on your data source here.

Once the dataset is defined, you need to make sure the Fields are properly loaded as expected. You can check this in the dataset property window itself and even after click “OK” and save it under the dataset you just created as shown below.

Now that we have set up our Dataset Source, then we can map this into our Parameter to load these data during the execution.

First thing, you need to make sure to set up the type of the Parameter, accordingly to the type of values that you’re loading from the dataset. In this example, “Text” would preferred.

So now, you can set up the Available Values with the “Get values from a query” option. You just have to select the dataset that you created as shown below.

Here you got Value field, which refers to the actual value that’ll be passed into the Report up on selection from the User. And then the Label field, that represents the display value of your dataset items, as you may have noticed in the previous steps.

Finally you set up the Default Values with the same set up, which will load the first item provided by the dataset query during execution into the Parameter, which will then trigger the loading of the Report data based on that.

Here make sure to set the same Value field selection as you set up on Available Value sections. 😉

Once the set up is done, you may see your Parameters now visible in the Design View of your RDL Report as shown below… 😀

You still need to set up the those Parameters as dependencies for your Report, which we will discuss next…

Let’s tie up Parameters with Report!

Here’s the final step fellas! 😀 Let’s open up the properties dialog of the dataset that you’re using to populate your Report,

Go to the Parameters section, and add the Parameters you just created in the previous step!

Yep it’s that simple! 😀 as you can see I have added the ReportParameter1 that I have created here, where as Parameter Name is set up as it is, and then the Parameter Value field is set up as [@ReportParameter1], which is how you address the Parameters you have defined in the Report. Subsequently you can add any number of Parameters following the same.

Notice how each Parameter set up has the Expression button next to it? that is to allow you to modify the value coming in from the Parameter using Expressions, if you wish to! 😉

Next you have to set up the Filter based on the Parameters that you just registered, so go to the Filters section, and add the filtering logic you require based on those parameter value for the repopulating of the Report data.

Right here you need to pay extra attention to details, where you need to consider which field in your data set you want to set up the parameters against for filtering, and what type of operator you need for this logic. You need to make sure both values you’re comparing are of the same type, and also you can modify their values based on Expressions before they’re applied for the filter.

As you can see above I’m using the DataField1 text field’s value to check whether its equal to the value given in the ReportParameter1 for each data row.

If I’m to show another example, take a look at below, I have added a second parameter which is type of Date/Time, which then compares itself with the value of DataField2 date/time field in the report dataset.

Now both those filters will act as an AND junction and filter out the data based on the combined logic. Save it up, you’re all set! 😀

Well… that’s how you tie up your Parameters with the Report’s dataset! 😉

You can now run this Report and see the beauty in action! 😉

Conclusion

Microsoft SQL Server Reporting Services – RDL Reports allows you to add Parameters to them, so that you could allow Users to filter the data according to different business logic for ease of analysis. You can add many different types of Parameters which could be used to filter the report data in kinds of different ways, using Expressions.

  • Define your Parameters in the RDL Report
  • Set up the available values for your Parameters
    • load data into Parameters based on specific list of values, or
    • load data into Parameters from a query based data set
  • Set up the Refresh action event
  • Add them as dependencies for your Report
  • Set up Report data filtering based on Parameters

This will allowing the Report data to be filtered dynamically based on the Parameter values that are passed in by the selections from the User. Well it is quite straight forward as you can see… 😉

Hope this little step by step guide helped someone, somewhere in the world… happy building my fellow devs! 😀

Share the love! 😀 Cheers!

Data formatting in SSRS RDL Reports with Field Expressions…

Let me share some exciting ways of formatting data with Field Expressions in SSRS RDL based Reports that I discovered during my Microsoft Dynamics 365 adventures! 😉

Using the Expression Builder in Visual Studio Report Designer, you can add all kinds of interesting ways of formatting your data for RDL Report projects. You can set custom expressions to these data fields to format and manipulate them easily.

This is where the magic happens, as you can see there’s a whole collection of library for formatting data with Expressions…

Backstory…

So I happened to be embarked on a Microsoft Dynamics 365 CRM data Reporting project, where I was tasked built a bunch of SSRS RDL based reports, that pulls data from CRM and format it based on the custom business logic before displaying to the user.

This involved writing a whole bunch of custom expressions on each field in those reports, where I came across all these interesting ways of formatting and manipulating data.

So here I am sharing some interesting field expression formatting that I discovered during that adventure… 😉

Formatting Fields with Expressions!

Opening up the Expression editor dialog you can see the long list of available syntaxes with their respective functionality description. It gives a good head start for whatever the function you’re looking to implement to format your data.

Alright then let me share some awesome stuff you can do with these data formatting functions available through expressions… 😀

– Lower case and Upper case…

=UCase(Fields!mytestfield.Value))

or for lower case,

=LCase(Fields!mytestfield.Value))

– Multiple fields into a Single field…

= Fields!mytestfield1.Value + " - " + Fields!mytestfield2.Value

You can pull data from multiple fields into a single field, and concatenate those field values using “+” operator, even add string chars in the middle as you wish.

– Check for null…

ISNOTHING(Fields!mytestfield.Value)

This will return a True or False boolean value based the value in the field.

– If conditions…

=IIf(ISNOTHING(Fields!mytestfield.Value),
" - ",
"DC-" + UCase(Fields!mytestfield.Value)))

As shown above this will check if “mytestfield” no value, then return ” – “, otherwise return the Upper-cased, custom value of “mytestfield” as “DC-XXXXX”…

– Switch statements…

=Switch(
Fields!mytestfield.Value = "1", "Monkey",
Fields!mytestfield.Value = "2", "Rabbit",
Fields!mytestfield.Value = "3", "Penguin")

Based on the value present in “mytestfield”, we return the response value.

– Text Trimming…

=RTrim(UCase(Fields!mytestfield.Value))

No trailing spaces (RTrim) at the end or similarly no leading spaces (LTrim) in the beginning of the value, or for both function in the same time use (Trim).

– To Date object…

=CDate(Fields!mytestfield.Value)

This will return a date object from the value present in “mytestfield”…

– Formatting a value…

=Format(CDate(Fields!mytestfield.Value), "dd/MM/yyyy")

This formats the value accordingly to the given date format, similarly this applies to any type..

– Format and Concat multiple fields into a single value…

= Format(Fields!mytestfield1.Value, "yy") + 
Format(Fields!mytestfield2.Value, "MM") + 
Format(Fields!mytestfield3.Value, "dd")

This format those different field values and merge them into a single field…

– Yesterday, Today, or Tomorrow…

=DateAdd("d",-1,Today())
=Today()
=DateAdd("d",1,Today())

First expression, gets the Yesterday’s date, second get the Today’s date, third expression gets the Tomorrow’s date…

You can also format is similarly,

=Format((DateAdd("d",-1,Today())), "dd/MM/yyyy")

Since it returns a date object no need to convert the value before formatting…

– Convert UTC date time object to local time…

=Format(
System.TimeZone.CurrentTimeZone.
ToLocalTime(Fields!mytesttimefield.Value), "hh:mm tt")

Here “mytesttimefield” carries a date time object with UTC time, and we’re now converting that to the local system time, whichever the timezone set up in the client environment…

– Extract Date object segments…

=Year(CDate(Fields!mytestfield.Value))
=Month(CDate(Fields!mytestfield.Value))
=Day(CDate(Fields!mytestfield.Value))

Three options, extract Year, Month and Date values from a given Date object…

– Build a Date object…

=DateSerial("2020", "06", "18")

Now that builds a date object by year, month, and date segments. If I’m to spice it up…

=Format(
   DateSerial(
   Year(CDate(Fields!mytestfield.Value)),
   Month(CDate(Fields!mytestfield.Value)),
   "1").AddMonths(1).AddDays(-1),
"dd/MM/yyyy")

You can also add extra values after build the date object as shown there.

Well that’s it for now… 😀

Conclusion

It’s actually quite fun to work with formatting or manipulating data using Expressions in SSRS RDL Reports, while the Expression editor window follows a great editing tool with descriptions of each function available.

There’s many awesome functions available in the Expression editor to format our data fields before presentation to the user during execution. You could build all kinds of custom formatted data values even by merging multiple fields. All this is quite straight forward and easy to use.

Share the love! 😀 Cheers!

Let’s set up Microsoft Dynamics 365 Fetch Extension in VS2015!

Let’s install Microsoft Dynamics 365 Fetch extension in Visual Studio 2015 for SQL Server Reporting Services, on Windows 10, out here in the year of 2020!

This is also known as Microsoft Dynamics 365 Report Authoring Extension, which is used for building data sources, for Reporting Projects, where it helps you establish the connection to the Dynamics 365 instance you require.

Backstory…

So recently I found myself working on a Dynamics 365 Reporting project module, where I had to pull data from the Dynamics 365 cloud, using a FetchXML query, process it through a set of business logic and then display to the user in a nice looking Report Layout.

This can nicely be done in a Report Server project in Visual Studio, but you need to have both the SQL Server Data Tools and Microsoft Dynamics 365 Report Authoring Extension (Microsoft Dynamics 365 Fetch Extension) set up installed in your Visual Studio.

But this whole environment set up is very much tricky these days, due to incompatibilities with latest versions of Visual Studio. So I had to go through a long roller coaster ride to figure this out, trying out different versions of the extensions and Visual Studio to get it to work.

So to save others from this painful roller coaster ride in a year like 2020, I’m documenting this process step by step for my fellow devs… 😉

Dynamics 365 Fetch Extension!

As I mentioned before, this also known as Microsoft Dynamics 365 Report Authoring Extension, is required for creating Data Sources in Report Server Projects, which is absolutely required for building Report Layout (RDL layout report). Since you need to define a valid data source before hand creating any Reports in your project.

Only for Visual Studio 2015!

The unfortunate situation is that this extension is only supported in Visual Studio 2015, quite surprisingly also there’s no support for this extension in any VS version beyond that.

Although there are some indirect hack ways to install this on VS 2017, it still doesn’t justify having to downgrade your whole Visual Studio Setup. So we might as well do a clean installation of Visual Studio 2015, and install this extension on top of it.

The Set up?!

So assuming you’re currently on latest Visual Studio version probably VS 2019 or beyond, the best choice would be to create a Virtual Machine on your Windows, and do a clean VS 2015 installation there and proceed with the extension set up.

If you don’t have resources to create a separate VM on your Windows, you could also resort to doing a fresh installation of VS 2015 in your dev environment, side by side with VS 2019. I’ve personally tried this method, since I was running Windows on Parallels in an Apple iMac.

So either choice is up to you, then let me get into the step by step walk through of this installation set up…

Let’s begin with VS 2015!

So let’s first go ahead with downloading VS 2015 from Microsoft Visual Studio older versions archive from the following link: https://visualstudio.microsoft.com/vs/older-downloads/

Here you’ll probably be asked to login, and directed to VS Subscriptions page, where you should be able to search for “Visual Studio 2015”

Select “Visual Studio 2015 Update 3” option, and web installer download will begin. Once the download completes, run the set up…

Once the installer loads up, select the “Custom” option,

This is to select only the “Microsoft SQL Server Data Tools” option only, since that’s our primary requirement here…

Once you’re done with selection, proceed with the installation…

Once the installation finishes, we need to next download the SQL Server Data Tools version that we require for this set up…

Setting up SSDT 17.4!

So let’s go to this link: https://docs.microsoft.com/en-us/sql/ssdt/previous-releases-of-sql-server-data-tools-ssdt-and-ssdt-bi?view=sql-server-ver15 and download SSDT for VS2015 17.4

Launch the installer and make sure to select the following options…

And let the installation process complete…

Now the SSDT for VS2015 installation finishes, next we need to download the Microsoft Dynamics 365 Fetch Extension…

Setting up Dynamics 365 Report Authoring Extension – Version 9.0!

In this step we go to this link, https://www.microsoft.com/en-us/download/details.aspx?id=56973 and download Dynamics 365, version 9.0 Report Authoring Extension (with SQL Server Data Tools support)

This will download the CRM9.0-Bids-ENU-i386.exe file, up on running it will ask you to choose a folder to extract itself. So select the current folder path and create a new folder for the set up. Once the extraction completes, the set up will begin itself.

Select the recommended option and click Next…

The next step will check for the required components and prompt you to automatically install them as follows…

Click the “Install” button and wait for it to complete.

Then click next, which will run a quick system check.

Once that’s done, click Next, which will begin the installation as follows…

Let it complete, and you should see the following up on success! 😀

Now the final step is done, let’s try this out!

Let’s try it out!

So to begin, open up your Visual Studio 2015, and select Business Intelligence -> Reporting Services -> Report Server Project, create a new project here. Or if you already had a Reporting Project created before, then open that up…

Let’s add a new Report to our project…

The new Report will be added and it will open up the Data Source window as follows, where you can see the Microsoft Dynamics 365 Fetch option is now listed up.

So go ahead, add your Dynamics 365 source and set up your Report as you wish!

Yay Success! Well that wasn’t so bad was it eh! 😉

Conclusion!

Well I’m not sure this actually requires a conclusion though lol 😀 Although I still can’t figure out why Microsoft Dynamics 365 Report Authoring Extension, is not supported in any VS version beyond VS 2015.

So keep in mind the extension for Microsoft Dynamics 365 Fetch option in your Data Sources list, which added by Dynamics 365 Report Authoring Extension – Version 9.0 is only available via the set up of SQL Server Data Tools version 17.4 with Visual Studio 2015.

Anyhow I hope this step by step guide saved someone the time required to figure out this set up, by trial and error. 😉

Share the love! 😀 Cheers!

So I played around with Android Emulators in Visual Studio 2019!

Let me share some of my experience with playing around with the latest updated Android Emulators in Visual Studio 2019!

Microsoft had finally rolled out a full fledged Android Emulator set up (Xamarin Android Device Manager) that’s very stable and much easier to use with Xamarin mobile development, expiring the previously buggy always-out-dated VS Emulator set up that was shipped for Xamarin dev. Yeah seriously I hated that and had a lot of issues using those emulators.

Backstory…

So recently I got a little deep into the new Xamarin Android Emulator set up in Visual Studio 2019, where I had to build a whole bunch of custom Emulators for some experiments. I had to do a lot of fine tuning and customization for those Android Virtual Devices. Also I had to focus on Performance management as well, which was quite interesting to deal with given the HAXM and Windows Hyper-V separation.

It was a great learning experience, where I noticed a lot of new features and differences between the previous VS Emulator set up compared to this one.

So here I am sharing my experience…

Getting Started…

Here are some important articles that might be important for anyone to get started…

Managing Virtual Devices with the Android Device Manager
https://docs.microsoft.com/en-us/xamarin/android/get-started/installation/android-emulator/device-manager?tabs=windows&pivots=windows
Great step by step guide on how to update Device Manager, create new Virtual Devices, Customizing and Managing the performance further…

Editing Android Virtual Device Properties
https://docs.microsoft.com/en-us/xamarin/android/get-started/installation/android-emulator/device-properties?pivots=windows
Step by step guide for Editing Virtual Device Properties…

Troubleshooting
https://docs.microsoft.com/en-us/xamarin/android/get-started/installation/android-emulator/troubleshooting?pivots=windows
Basically this includes fixing HAXM issues, Hyper-V issues not configured up in BIOS, or not Enabled in Windows, etc.. It’s quite easy to miss those configurations so you might want to focus twice on those if you ever run into any issues.

The official documentation from Microsoft does a great job of explaining how to get started and all, so I won’t be repeating the same on my blog post, rather I would focus on the important bits that I experienced and issues I ran into which I eventually solved during my playing around! 😉

The adb binary is obsolete!?!

So this is the first weird issue I ran into when I tried out the Android Emulator on Visual Studio 2019, there is a reason why I call it weird though… lol

“The ADB binary found at C:\Program Files (x86)\Android\android-sdk\platform-tools\adb.exe is obsolete and has seriousperformance problems with the Android Emulator. Please update to a newer version to get significantly faster app/file transfer.”

Yeah notice the “seriousperformance” lol, no idea why they haven’t spell-checked the error message. Anyhow I kept on getting this warning message every time I launched my Android Emulators, I couldn’t really understand why, since I had VS 2019 updated to the latest version at the time. But later only I figured out that you need to manually update some other bits from your Android SDK Manager as shown in below steps…

Update Android Emulator!

You need to make sure to update your Android Emulator version, from the Android SDK Manager as shown below…

Go to the Tools tab, and expand the Android Emulator section, make sure you have installed the latest version as shown there. Most likely this won’t be updated by the usual VS Updater process, which was the issue in my case.

Also one more thing you need to do, since the “obsolete ADB binary issue” could be occurred from either one of these.

Update Android SDK Build Tools!

Go to Tool tab and expand Android SDK Build Tools section…

You need to make sure to have the latest version installed, and remove any older versions already installed of the Android SDK Build Tools as shown above. Because this could be causing the “obsolete ADB binary issue” that I mentioned earlier.

Intel HAXM vs Windows Hyper-V!

Now some devs seem to be getting confused about this, first think of it as this, you have an Android Emulator and you have these two different support systems that you can use to accelerate the performance of it. You can use only one of them, its either Intel HAXM or Windows Hyper-V, you cannot use both at the same time. Got it? 😉

Check out the docs: Hardware acceleration for emulator performance (Hyper-V & HAXM)
Well the documentation from Microsoft does a great job at explaining both these setups in great detail step by step.

I personally tried both of them separately in my Lenovo Windows Laptop, that’s running on Intel Core i7 Processor. Keep in mind, if you want to try Intel HAXM then you need to disable Windows Hyper-V and vise-versa, otherwise you’ll run into all kinds of issues.

Aha! Intel HAXM!

Intel’s Hardware Accelerated Execution Manager (HAXM). HAXM is a virtualization engine for computers running Intel CPUs. – Source

Check if your Intel Processor supports Virtualization Technology: https://www.intel.com/content/www/us/en/support/articles/000005486/processors.html

You development machine needs to be running on an Intel processor in order for HAXM to work, even in that case that processor needs to support Intel VT, you can check it from the link I shared above. This works on both Microsoft Windows and Apple Mac OS systems, as long as the hardware requirements are met.

Intel HAXM has always been there since long time back for accelerating the performances of Android Emulators, so it supports Emulators that are running older versions of x86-based virtual devices.

If you’ve successfully set up Intel HAXM, you can check status of HAXM set up as follows:

sc query intelhaxm

Microsoft recommends this option to be your default choice for setting up your Android Emulators. But if your dev set up doesn’t support Intel HAXM acceleration, next let’s see the second option…

Ooo! Windows Hyper-V!

Microsoft’s Hyper-V and the Windows Hypervisor Platform (WHPX)Hyper-V is a virtualization feature of Windows that makes it possible to run virtualized computer systems on a physical host computer. Source

As obvious as it is, this only works on Windows OS! This was introduced for Android Emulators quite recently, so you need to have the following set up for your local Android SDK and Tools:

  • Android Emulator package 27.2.7 or later
  • Android SDK Tools version is 26.1.1 or later

Also you need to have Microsoft Windows 10 Pro, Enterprise, or Education version installed. You can check if your system could support Windows Hyper-V as follows:

systeminfo

If all those values are shown as Yes, then you can go ahead and enable Windows Hyper-V on your machine 🙂

So, Intel HAXM or Windows Hyper-V!?!

Yeah, so which is better? given that you can ONLY think of if you’re development PC is compatible for both of them!

I’ve tried both of them, and to be honest I’ve seen much better performance with Intel HAXM Acceleration in my Windows 10 Lenovo Laptop, with Intel Core i7 processor. Since Microsoft docs also recommend this option, yes I would definitely recommend this be your primary choice as well for better performance.

FastBoot, Intel HAXM only!

Now this is something strange that I noticed during my try outs, FastBoot feature does not seem to be supported on Windows Hyper-V, during every launch it was executing a fresh cold boot. But with Intel-HAXM it works like a charm! So that’s probably something you need to keep in mind! 😉

If you’re not familiar with FastBoot, let me walk you through a little intro…

FastBoot vs ColdBoot!

You can see this configuration in the Properties from the Android Device Manager as following…

FastBoot allows you to directly boot your Android Emulator from a pre-saved snapshot state image, so you get a super fast boot and be able to deploy the apps faster when you launch directly from Visual Studio. Every time you close the Emulator it will save a snapshot of it’s current state, which will be used in the next boot.

So what is ColdBoot?

The opposite of FastBoot is ColdBoot, where during every launch the Android Emulator executes a fresh boot instance. ColdBoot is by default disabled as you can see in my previous screenshot, you need to tick on the fastboot.forceColdBoot in order to enable this. You should only use this if you need a fresh boot in each time your Emulator launches.

Now as obvious as it is, keep in mind you can’t use both of them at the same time, so make sure to tick on either forceColdBoot or forceFastBook as you prefer. 🙂

Maximum performance!

For maximizing the performance of your Android Virtual Device, I found utilizing on these three properties quite useful,

  • hw.gpu.mode – the GPU allocation set up of your Emulator
  • hw.cpu.ncore – number of Processor Cores allocated to your Emulator
  • hw.ramsize – amount of RAM size allocated to your Emulator

Now the higher values you set for those properties will definitely provide better performance in your Android Emulator, but it will require consumption of more resources from your development machine, so make sure to cross check against it when you tweak those up!

hw.gpu.mode -> host!

By default this property will be set to “auto” mode which will set the Emulator to decide whether to use device GPU processor to render the Emulator’s GPU processing or use Software GPU Emulation.

If you’ve got a dedicated powerful GPU in your development machine, I would say this should set the “host” option for the GPU emulation in the Emulator, which forces the Emulator to use the system GPU device, which in return provides great performance.

New Camera magic!

Since the latest update Android Emulators are now updated with an awesome Camera emulation feature which allows you to emulate a virtual 3D scene. You can enable this by setting the hw.camera.back property to virtualscene value.

This is such an awesome feature it allows you to navigate through an emulated virtual scene in a 3D space, with full 360 degree camera angle movements.

Now that’s some awesomeness eh! 😉

LCD Density!

You can set the density of the screen in your Android Emulator, to a list of custom values possible to set up the density-independent pixels for rendering.

Keeping in mind, setting hw.lcd.density to 160 value will cause the emulator to render each pixel in the device screen equivalent to your host machine’s physical screen pixels. You should be able to find the most suited screen density for the screen resolution you have set up for your emulator.

Here’s an example of screen resolution 1080×2160 with each lcd screen density option available from 160, 240, 213, 320, 420, 480, to 560 as follows…

Well well you can see how it clearly changes the UI rendered DPI based on the density settings you have set up… 😀

Custom Resolutions play!

So one tricky thing I got to play around was creating Android Emulators with custom screen resolutions, now this really requires a careful set up of the screen Density settings as well.

So for the fun of let me show you a custom Android Emulator that I build with the screen resolution equivalent to iPhone 11 which has height to width 1792×828 resolution…

So something to keep in mind is that, right on the first try you wouldn’t get screen density property compatible for the custom screen resolution, so you will need a few try outs to sort out the density property. Yes it took a few try outs for me as well! 😉

hw.lcd.height – screen height, hw.lcd.width – screen width, hw.lcd.density – screen density

Setting up skin.path value…

When you set up a custom resolution to your Emulator, you need to make sure to update the skin.path property value as well.

Set this value followed by the format resolution, widthxheight as shown here.

Not sure how this related to the custom resolutions, but if you miss this step your emulator screen will end up with the default resolution value set up here upon create. So make sure to set this value according to your custom screen resolution as well 🙂

Enabling on-screen Keys…

[ back | home | recent ] yes those on screen keys might not be available when you first create your custom emulator, to enable this you need to disable the hw.mainKeys property.

You should un-tick this property value to enable on-screen navigation keys.

And the resulting should be as straight as below… 😉

Well there you have it, working like a charm! and that’s pretty much it for all the tricks and lessons that I learned during my playing around with Android Emulators in Visual Studio 2019!

Conclusion

The latest updates to Android Device Manager allows you to create Android Virtual devices or emulators with incredible flexibility and easy to manage interface, with improved performances and enhancements unlike before. 🙂

The Microsoft documentations provide an incredible support for getting started step by step, and even customizing your Android emulators for Xamarin Development with ease.

I happened to be stumbled upon a great opportunity to learn a few tricks and lessons for complex use of the latest Android Virtual Devices for Xamarin Development, which I had shared in this article. 😉

Hope it helps any of you fellow devs out there!

Share the love! Cheers! 😀

Pushing the limits of Hybrid WebView in Xamarin.Forms!

Let’s push the possible limits of Hybrid WebView and build something awesome in Xamarin.Forms! 😀

Remember my last blog post, Building a bi-directional interop bridge with WebView in Xamarin.Forms! which is where I shared about building a bi-directional invoke bridge between Javascript and C# dotnet run time using Hybrid WebView.

So based on that I went on a little journey to push the limits of this Hybrid WebView and built some cool demos with it. So here I am sharing it all with yol! 😉

Pushing the limits!

BTW: This is going to be a continuation of my previous blog post, so better take a look at it first if you haven’t: Building a bi-directional interop bridge with WebView in Xamarin.Forms!

To put it into fancy words,

We built a bi-directional communication bridge, between completely different run times, with possibility of two way execution invoke on demand! Hybrid WebView…

So now, the question is, what can we do to push the limits of our Hybrid WebView? Sounds like something for the imagination to limit!

Behold the awesomeness!

Imagine, being able to load a Web page into you Xamarin.Forms WebView, and being able to access Device features such as Camera, GPS Location, Accelerometer, etc..

Basically we’re going access Device Native features through the WebView and retrieve data directly from C# .NET run time in our Xamarin.Forms app! You will be able to load any HTML content, either from a Web Hosted source or locally generated HTML source, it would work like a charm thanks to the Hybrid WebView!

In order to demonstrate this awesomeness, let’s try out the following feature for the demo implementation…

  • Capture Photos using Device Camera
  • Pick Photos from Device Gallery
  • Get Device Native information
  • Get Device GPS Location data

All those device features and data will be accessed from the Javascript running inside the Hybrid WebView! 😉

Like I mentioned before, we will have two HTML sources for this demo, a web hosted HTML source and a locally generated HTML source to make sure it works for either cases! 😀

Now here’s a bit about what will help us build this awesome demo..

– Bi directional bridge!
Being able to invoke executions directly between the Javascript environment and C# .NET Xamarin.Forms run time, is what is going to help us build this awesomeness!

Javascript <~> Xamarin.Forms (C# .NET)

So you can pass data from the Javascript that’s running inside the Hybrid WebView out into the C# .NET run time, as well as you can pass data directly into the Javascript that’s running inside the Hybrid WebView.

– Multiple parameters…
In my previous blog post I mentioned this at the end where you can extend the same implementation we did for our Hybrid WebView, into supporting multiple parameters, so here I will use this to demonstrate what we’re going to build!

Sneak Peak!

Now here’s some action on the go with this awesomeness… 😉

As usual I’ve hosted this whole demo project up on my github repo:

Code on github: https://github.com/UdaraAlwis/XFHybridWebViewAdvDemo

This is how we do it!

So let’s get right into it, but first let’s make sure some prerequisites.

– Basic Hybrid WebView implementation
Refer to my previous post and check out the implementation of the Hybrid WebView. Building a bi-directional interop bridge with WebView in Xamarin.Forms!

– Xamarin.Essentials set up to access the device native feature
You need to implement Xamarin.Essentials and set up all the device native features and their configuration for the features you wish to use. https://docs.microsoft.com/en-us/xamarin/essentials/

Multiple Parameters support!

Let’s begin with adding support for multiple parameters in our Hybrid WebView as follows…

public class HybridWebView : WebView
{
	private Action<string, string> _action;

	public void RegisterAction(Action<string, string> callback)
	{
		_action = callback;
	}

	public void Cleanup()
	{
		_action = null;
	}

	public void InvokeAction(string param1, string param2)
	{
		if (_action == null || (param1 == null && param2 == null))
		{
			return;
		}

		if (MainThread.IsMainThread)
			_action.Invoke(param1, param2);
		else
			MainThread.BeginInvokeOnMainThread(() => _action.Invoke(param1, param2));
	}
}

Code on github: /XFHybridWebViewAdvDemo/Controls/HybridWebView.cs

As you can see, I have defined Action property with two parameters, along side the setter method of it, RegisterAction() accepts Action instances with two parameters.

InvokeAction() which gets called from each native renderer level now accepts two parameters accordingly. As an addition I have added an enforced UI Thread execution using Xamarin.Essentials.MainThread feature, since we’re going to access IO heavy device features.

Following the same pattern you can add as many number of parameters as you wish! 😉

We need to add support for this in our Javascript implementation as well, so we create a pre defined separator (a pipe separator preferably “|”) that separates parameters in the data object we’re sending from javascript to Hybrid WebView’s Renderer’s script handler.

..
invokexamarinforms('PHOTO|CAMERA')
..

When our Hybrid WebView renderers receive the invoke from Javascript, we need to handle the incoming data object as follows by splitting it up using the separator we defined…

var dataBody = data;
if (dataBody.Contains("|"))
{
	var paramArray = dataBody.Split("|");
	var param1 = paramArray[0];
	var param2 = paramArray[1];
	((HybridWebView)hybridRenderer.Element).InvokeAction(param1, param2);
}
else
{
	((HybridWebView)hybridRenderer.Element).InvokeAction(dataBody, null);
}

Then we pass it on to the InvokeAction() event, for Xamarin.Forms level to handle whichever the Action has subscribed to it. This way you can handle as many parameters as you wish!

Launch invoke from HTML Javascript to C# .NET!

So here’s how we set up the simple implementation to call up the invokeXamarinFormsAction() method that we have defined in our Hybrid WebView platform Renderers. Well there’s not much different from what we implemented in my previous demo, but here we are passing multiple parameters into the javascript method upon the button click.

...

<script>
...
function invokexamarinforms(param){
    try{
        invokeXamarinFormsAction(param);
    }
    catch(err){
        alert(err);
    }
}
</script>

...

<button type="button" 
	onclick="invokexamarinforms('PHOTO|CAMERA')">
	Get from Xamarin.Forms</button>

...

This is something I’ve explained step by step in my previous blog post so I wouldn’t go into details in here. You can define as many onclick actions as you wish with the set of predefined parameters like “PHOTO|CAMERA” and “PHOTO|GALLERY”, even single parameters, “GPS” and “DEVICEINFO”, etc…

Next you need to handle those parameters in C# code to execute the specific action we’re targeting, as simple as a if-else block as follows, or even a switch statement would suffice.

...

private async void ExecuteActionFromJavascript(string param1, string param2)
{
	...	
	if (param1 != null && param1.Equals("PHOTO") && param2.Equals("CAMERA"))
	{
		var result = await _deviceFeaturesHelper.TakePhoto(this);
		if (result != null)
		{
			...
		}
	}
        ...
	else if (param1 != null && param1.Equals("DEVICEINFO"))
	{
		var result = await _deviceFeaturesHelper.GetDeviceData();
		if (result != null)
		{
			...
		}
	}	
	...
}

Based on the requested action we execute it in C#, in this case accessing Camera and Capturing a photo _deviceFeaturesHelper.TakePhoto() or even getting Device Native information _deviceFeaturesHelper.GetDeviceData() as shown above.

Let’s move to the next step of this chain…

Ping back from C# .NET to HTML Javascript!?

Now that we established pathway to call the C# .NET run time from Javascript, we’re able to invoke any action, but how do we get back the result data into the Javascript?

So in my previous blog article Talking to your WebView in Xamarin.Forms! which explains how easy it is to pass data into the Javascript rendered inside the WebView at run time, since our Hybrid WebView is an extension of the default WebView, we can use the same method here…

...
        var result = await _deviceFeaturesHelper.GetDeviceData();
        if (result != null)
        {
             await webViewElement
                   .EvaluateJavaScriptAsync($"setresult('{result}')");
        }
...

So we’re calling up on EvaluateJavaScriptAsync() with the Javascript function name that’s accepting to the results for this specific action. This function needs to be created inside the Javascript before hand, that is rendered inside the Hybrid WebView as follows…

...
<script>
...
	function setresult(value) {
		// - display the value in HTML
		// - send the data to server
	}
</script>
...

Once the data is passed into your Javascript function, You can do whaever you want with the data, be it display in the HTML, or send it up to a web server, your choice! 😉

Calling the Device Native!

Well this is quite simple if you know how to use Xamarin.Essentials to access device native features and other 3rd party plugins to access various features from Xamarin.Forms! But I’ll quickly walk through the code that I’m using in this demo.

I’ve basically created like a little Facade layer which handles all the device native features required as follows, and each method handles a given specific feature such as Camera and GPS features using their respective services of plugin calls…

public class DeviceFeaturesHelper
{
	public async Task<string> TakePhoto(ContentPage pageContext)
	{
		// launch Media Plugin to capture photos from camera
	
		...

		return imageAsBase64String;
	}
	
	public async Task<string> GetDeviceData() 
	{
		// launch Xamarin.Essentials to load device info

		return $"{nameof(DeviceInfo.Model)}: {device}<br />" +
			$"{nameof(DeviceInfo.Manufacturer)}: {manufacturer}<br />" + 
			$"{nameof(DeviceInfo.Name)}: {deviceName}<br />";
	}
}

Code on github: /XFHybridWebViewAdvDemo/DeviceFeaturesHelper.cs

So what you need to keep in mind is that we need to return a value that’s compatible to be displayed inside our WebView, based on HTML, that’s why you see I have modified some of those returned values accordingly, such as Image objects are returned as base64 strings and device information formatted as a text block with <br /> inline.

These methods are called from the Hybrid WebView’s Invoke action that we created before and results are returned to be pushed back into Javascript.

Handling Media Image objects…

Using Media Plugin for Xamarin.Forms, provides you with a MediaFile object which contains the Image object that you acquired either from Camera or Gallery, but how do we convert that into something that’s compatible to be pushed into Javascript-HTML environment?

The solution is,

MediaFile -> byte[] array -> Base64 string

We’re going to convert our MediaFile object into a byte[] array, then convert again into a base64 string, which makes it so much easier to transfer the data into the javascript run time and use that object for any purposes inside javascript itself. Here’s my code snippet for this…

public async Task<string> TakePhoto(ContentPage pageContext)
{
        ...
	var file = await CrossMedia.Current.TakePhotoAsync(...);

	// Convert bytes to base64 content
	var imageAsBase64String = Convert.ToBase64String(ConvertFileToByteArray(file));

	return imageAsBase64String;
}

private byte[] ConvertFileToByteArray(MediaFile imageFile)
{
	// Convert Image to bytes
	byte[] imageAsBytes;
	using (var memoryStream = new MemoryStream())
	{
		imageFile.GetStream().CopyTo(memoryStream);
		imageFile.Dispose();
		imageAsBytes = memoryStream.ToArray();
	}

	return imageAsBytes;
}

This is what you saw in the previous section which I have used in my /DeviceFeaturesHelper.cs
You can use this in the javascript functions as easy as below,

function setresult_takephoto(value) 
{
	document.getElementById("photoCamera_ResultElement").src 
                                             = "data:image/png;base64," + value;
}

Well that’s the entire set up of this awesome demo, so then let’s see it in action…

Fire it up!

Here’s the web page we’re loading: https://testwebpage.htmlsave.com/

Look at em on fire, Android, UWP and iOS side by side…

Code on github: https://github.com/UdaraAlwis/XFHybridWebViewAdvDemo

Conclusion…

This was just me pushing the limits of the Hybrid WebView to build awesome stuff with Xamarin.Forms! This will definitely come in handy whenever you get a scenario you need to implement an existing Web App into a Xamarin.Forms app, and you need to let the user use it as a Mobile App, with being able to access device native features.

Well that concludes it. Hope you find it useful!

Share the love! 😀 Cheers!