XAMVVM-03 SpecFlow BDD UnitTesting with Xamarin.Forms!

Let’s explore the possibilities of the awesome SpecFlow Behavior Driven Testing Framework with Xamarin.Forms!

I’m a huge enthusiast of writing clean and highly testable code, and in that pursuit, I believe Test Driven Development for the win! 😉 Oh also, UnitTesting for life yo! 😛

Problem with just UnitTests!

They’re very useful when we need to sure there’s nothing broken in the logical code, but the only problem is that, they’re way too technical. They don’t really make much of a sense to a non-technical person, since its all code and logic based and the out put is not really human friendly (for a non techie).

Why Human-Friendly testing?

Software Development process is not just a technical dev fellow write the code and deploy to the user process, its way more complicated and involves a lot of parties. Whether you like it or not modern day Software are purely driven by Business Requirements, which includes a lot of non-technical parties into the Software Development cycle. Business fellows, Testers, Analysts and Developers all come together to develop systems nowadays.

This is why we need a more human-friendly and human-readable way of executing the testing process, that can be shared among all the stake holders and could make sense to them from the beginning to the end of the SDLC.

This is where Behavior Driven Development comes into play, it defines a common ground that can be shared among all the stakeholders that are involved in a development of a software, from a techie to a non-techie, from Developers, Testers, QA Engineers, to Business Analysts and even directly to the Customer.

Behavior Driven Development!

BDD tests are written in a way that it is easily understood by everyone, even before the development life cycle begins, while making sure the requirements are specific and well defined. Every single feature is broken into scenarios with specific test steps that make sure behavior is executed as expected, thus behavior driven development 😉

These tests are written in a format called Gherkin, is a business readable and domain specific language created for writing BDD tests. Here’s a little example:

“Feature” tag explains the functionality of a feature, and a single Feature could contain many “Scenarios” that tests the functionalities related to that Feature. Each scenario has steps where you combine the actions using the Given, And, When, Then keywords. 🙂 Simple as that eh! 😀

We could also interpret it almost same as Test Driven Development based UnitTesting but with an extra awesome layer of icing called Behavior Driven Development!

Cucumber and SpecFlow!

Now in order to actually implement these BDD Tests using Gherkin syntaxes, we used a framework called Cucumber, which is a Ruby based framework!

But when it comes to .NET we have an awesome wrapper framework for Cucumber called SpecFlow, that provides us with all the goodness of BDD Testing.

SpecFlow is open source and provided under a BSD license. As part of the Cucumber family, SpecFlow uses the official Gherkin parser and supports the .NET framework, Xamarin and Mono.

SpecFlow seamlessly integrates with Visual Studio and provides all the functionality and features required to carry out your BDD life cycle.

Following a Pattern…

Although SpecFlow constructs its Tests based on Features, you could organize your Test cases as you wish, either based on Pages, Application Flows, or even Features themselves.

Page based pattern – based on behavior and functionalities available in each page in the application, such as example Home Page, Shopping Cart Page, Payment Page, and etc…

Application Flows – based on each individual feature flow of the application, such as Login Flow, Order Flow, Payment Flow, and etc…

Features – based on each individual feature flow of the application, such as Login Feature, Order Feature, Payment Feature, and etc… (quite a bit similar to App Flows)

You could also mix and match between those pattern, based on your requirements or the complexity of your application.

SpecFlow with Xamarin.Forms!

Since SpecFlow bring the beauty of Gherkin-BDD  goodness to .NET we can directly use it in our Xamarin.Forms project solution as well any .NET project solution.

We’d basically be setting up our Xamarin.Forms project with a basic UnitTest project, and we’d add SpecFlow set up and configuration on top of it. In one of my previous blog posts I’ve explained how to set up Xamarin.Forms with UnitTesting project XAMVVM-02 UnitTesting with Xamarin.Forms!, hence I won’t be getting into that details, but rather focus on the set up of SpecFlow tid bits. So I would recommend taking a sneak peek at it before continuing here…

In a gist, we’ll create a UnitTesting project with SpecFlow set up and add our Xamarin.Forms project reference to it. Then we add Xamarin.Forms.Mocks library, for mocking Xamarin.Forms runtime during our test executions. Then we set up our Test App instantiation, with all the required dependencies, which is going to be used across all our test cases.

Once our Test project is ready, instead of writing usual unit test cases, we’d be writing SpecFlow test cases using Spec Feature files. Those Feature files have a C# code behind that’s bound to it which is where we’ll be implementing our test code logic and assertion.

That’s pretty much it! pretty straight forward eh! 😉 Let’s try it out…

Let’s get started…

So before we begin you need to make sure you have the SpecFlow for VS extension installed, if you haven’t, please install from the VS Marketplace which is completely free.

SpecFlow provides a wonderful documentation about how to get started: https://specflow.org/getting-started/ but it delivers for generic .NET projects, not specific for Xamarin. But I would still encourage you take a look through it first just to get some clarity!

Demo Overview!

Now that’s out of the way, let me tell you how I’m going to showcase the use of BDD SpecFlow UnitTesting in your Xamarin.Forms project.

Just for showcasing of this awesomeness, I’ve prepared a simple Xamarin.Forms project application, where you can create simple notes, attach location data, attach created date time values and store them locally, allowing you to view them at any time in a list of items. Quite a simple text-pad-like app.

I’ve named this project solution as, XFTextpadApp and it uses Prism as the MVVM framework.

As you can see above is a view of the project structure with the complete MVVM set up. Let me also share a bit of showcasing of the app and its features to give a more in depth context.

Here’s a little peek into features of this demo Xamarin.Forms Textpad app running on iOS!

In the Home page you can view the List of Texts you have saved. By clicking on a Text item in the Home page list you can view that Text item in detail in the View Text page. Then once you click the “New Text” Button it will take you to the New Text page where you can create and save new Texts…

In the New Text page you can create new Texts with a Title and Description of your Text and click “Save” button to save it with the Location and Time data attached to it.

Then you will be navigated back to Home page. In the Home page Text list you can delete saved Text by using the context menu as well…

Thanks to Xamarin.Forms we can deploy it directly to iOS, Android, and UWP as well! 😉

Now the App project is ready, we need to add Test project to it.

Hands on time!

Let’s begin by adding the Test project to our Xamarin.Forms project, create a new folder in the solution, named as “Tests” and then right click on it -> Add -> Add New Project

Now this is where the choice is absolutely up to you, as to which testing framework to choose from. Just for this demo, I’m gonna use MSTest Test framework, hence I will select MSTest Test Project (.NET Core) template and create our test project…

I will be naming the test project as, XFTextpadApp.SpecFlowTests making sure to stick to the standard naming practices! You might want to pay some attention to the Project Path there as well, where as to make sure we set the path to be inside the “Tests” folder that we created earlier.

Setting up SpecFlow!

Next let’s set up SpecFlow in our Test project, by adding the following SpecFlow nugets using the Nuget Package Manager!

  • SpecFlow
  • SpecFlow.MsTest
  • SpecFlow.Tool.MsBuild.Generation

Make sure to add them all in same version for compatibility reasons, as shown below.

One thing to note here that, I’ve added SpecFlow.MsTest package, while the official SpecFlow documentation recommends adding SpecRun.SpecFlow. The reason is, in order to use their recommended test runner, SpecFlow+ Runner (which is configured by SpecRun.SpecFlow), you need to have a registered SpecFlow account. Therefore I’m using the SpecFlow.MsTest test runner engine instead! 😉

If you need to access the full set of enterprise-grade large scale features of SpecFlow+, then you need to use their SpecFlow+ Runner.

Also if you’re using an alternate test framework like NUnit, or xUnit, then you need to use their own counterpart test runners here, such as SpecFlow.NUnit or SpecFlow.xUnit packages and so on. For more information here: https://specflow.org/documentation/Unit-Test-Providers/

Setting up the rest…

In order to complete rest of the set up, let’s add a reference of the host XFTextpadApp .NET standard project into our XFTextpadApp.SpecFlowTests project. Then we’re going to add our Xamarin.Forms Mocking library, Xamarin.Forms.Mocks.

Just to make sure we write some beautiful test code, let’s add Shouldly nuget as well. This is more of a personal choice 😉 or if you prefer you could use the default assertions of MSTest (MsTest.Framework.Assert), or which ever the test framework you have chosen to set up.

If all went well then you should see the Test project’s references set up as above. Now that’s out of the way, next on let’s get into coding!

Create app instance…

You could directly use the existing App class instance inherited from the Xamarin.Forms project within our Test project environment, or you can construct your own custom App instance that’s catered for the Test environment, which is what we’re going to do in this step…

Something to note here is that, the way you construct your Test App instance is completely dependent on how you have constructed your Xamarin.Forms application, so try to duplicate it as much as possible.

Let create a new class called TestApp in our XFTextpadApp.SpecFlowTests project root.

public class TestApp : PrismApplication
{
    public TestApp() : this(null) { }
 
    public TestApp(IPlatformInitializer initializer) : base(initializer) { }
 
    protected override async void OnInitialized()
    {
        ...
         
        await NavigationService.NavigateAsync("NavigationPage/HomePage");
    }
 
    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.RegisterForNavigation<HomePage>();
        ...
 
        containerRegistry.GetContainer().RegisterType<HomePageViewModel>(new Unity.Lifetime.ContainerControlledLifetimeManager());
        ...
    }
}

Now, you need to make sure to register all your Pages, ViewModels and Services accordingly. Also notice that how I have set up the default start up navigation in the OnInitialized() method according to Prism.

Next the Hooks…

This is more like the helper class that we’ll be using to set up the necessary hooks for our SpecFlow test run time environment, such as instantiating the App instance object, and initialising MockForms. Here we’re going to keep a public static object of our App instance, which we will use all across out tests cases. Let’s create a class called TestHooks

[Binding]
public class TestHooks
{
	public static TestApp App { get; private set; }
	
	[BeforeScenario]
	public void BeforeScenario()
	{
		Xamarin.Forms.Mocks.MockForms.Init();

		App = new TestApp();
	}

	[AfterScenario]
	public async void AfterScenario()
	{
		// After Scenario steps

		// 1. Clear App data in memory
		Application.Current.Properties.Clear();
		await Application.Current.SavePropertiesAsync();

		// ...
	}
}

SpecFlow provides Before and After Scenario handlers which we can use to perform operations as we see fit, hence I’m using [BeforeScenario] attribute with the BeforeScenario() method to initialise MockForms library and the app instance before each scenario. Scenario refers to a single test case, inside of a Feature in SpecFlow. Similarly [AfterScenario] attribute is used for cleaning up operations after scenario execution before. The [Binding] attribute is a marker informing SpecFlow that this class may contain hooks or step definitions, thus enabling the before and after handlers.

SpecFlow provides many different binding hooks like these that you can adopt for handling many different scenarios: https://specflow.org/documentation/Hooks/

You may have noticed the public static TestApp object here, which is the App instance that we’re going to use across all our test cases.

Alright, but we’re not done yet!

Creating the Features and Scenarios!

As I’ve explained before, in SpecFlow we create Features, then inside those Features we create Scenarios, in each Scenario we create Steps, and finally we bind those Steps to Step Definitions in C# code behind! Check out the extended explanation here: https://specflow.org/documentation/Using-Gherkin-Language-in-SpecFlow/

Now that all is set up and ready to go, let’s create our actual Tests. But first create a “Test” folder in the root of our XFTextpadApp.SpecFlowTests project.

If everything is well set up until now, then it should look like the above structure.

In the beginning I explained about following a pattern for organizing your SpecFlow Tests, and for this demo I will be following a Page context based pattern for my Tests.

So let’s consider our Home Page and one of its testable scenario such as,

Scenario:
First time I launch the app
I am Navigated to the Home page
I see an empty list of data
I see a label indicating empty data

Now let’s create our first Feature by, right click on the “Tests” folder -> Add -> New Item -> select SpecFlow in C# Items list -> select SpecFlow Feature File. Let’s name it as HomePage.feature and Add it.

You should see the HomePage.feature file created in your project, with some default SpecFlow content in it. Let’s replace all the default content with the following,

Feature: HomePage

Scenario: App Launching First Time Test
          Given I have launched the app
          Then I am in the Home Page
          And I can see 0 Items in Text List
          And I can see a Label indicating empty Text List

So in here you can see how I’ve defined our Feature as the HomePage, and then created the first Scenario accordingly. There we just created our first Feature and Scenario! 😉

One thing to note here is that, once you type out those steps, they’re highlighted in purple color. This is because those steps are not bound to any steps definition.

Until we create a Step definition file and bind those steps to the C# code behind, they’d stay highlighted in purple. Remember I told you, each test scenario is a combination of Steps and their C# code behind definition?! 😉

So next on, let’s create our Step definition file for our Feature by, right click on the “Tests” folder -> Add -> New Item -> select SpecFlow in C# Items list -> select SpecFlow Step Definition. Let’s name it as HomePageSteps.cs and Add it.

You will see the HomePageSteps.cs class generated with a bunch of templated code. Let’s remove all the auto generated code except for the following bits, with Constructor and private ScenarioContext object.

[Binding]
public sealed class HomePageSteps
{
	private readonly ScenarioContext _context;

	public HomePageSteps(ScenarioContext injectedContext)
	{
		_context = injectedContext;
	}
}

So this is the class where we will be creating our Step definitions for our Feature Scenarios. Notice the [Binding] attribute which marks this class as a candidate for step definitions. The constructor inject ScenarioContext provides you access for passing data between different Scenarios and Steps. More info: https://specflow.org/documentation/scenariocontext/

SpecFlow extension in Visual Studio allows us to generate the C# definitions for the scenario steps that are unbound. So let’s generate the step definitions for our HomePage.feature Feature and its Scenario that we created before.

Open the HomePage.feature file and right click anywhere inside the feature file. Then select the menu option at the bottom, “Generate Steps Definitions“, which will popup the following,

Here you can use the Copy methods to clipboard button and paste these generate C# definitions in your HomePageSteps.cs class file. If you select generate it will generate the whole steps file for you, and ask you to select the folder destination to save the file.

So after generating the step definitions our HomePageSteps.cs class file should be updated as shown below, (I’m show only one definition here in the code)

[Binding]
public sealed class HomePageSteps
{
	...

	[Given(@"I have launched the app")]
	public void GivenIHaveLaunchedTheApp()
	{
		ScenarioContext.Current.Pending();
	}
	
	...
}

By default the generated code will add the ScenarioContext.Current.Pending(); line for marking the step as pending. You can go ahead and remove that in all the steps and let’s complete our Test implementation…

[Binding]
public sealed class HomePageSteps
{
	public TestApp App => TestHooks.App;

	[Given(@"I have launched the app")]
	public void GivenIHaveLaunchedTheApp()
	{
		// Is the app init and running
		App.ShouldNotBeNull();
	}

	[Then(@"I am in the Home Page")]
	public void ThenIAmInTheHomePage()
	{
		var navigationStack = ((NavigationPage)App.MainPage).Navigation.NavigationStack;
		// Am I in the Home page
		navigationStack.Last().BindingContext.GetType().
		    Name.ShouldBe(nameof(HomePageViewModel));
	}

	[Then(@"I can see (.*) Items in Text List")]
	public void ThenICanSeeItemsInTextList(int itemCount)
	{
		// Checking the number of items in the List
		App.Container.Resolve<HomePageViewModel>().
		    TextList.Count.ShouldBe(itemCount);
	}

	[Then(@"I can see a Label indicating empty Text List")]
	public void ThenICanSeeALabelIndicatingEmptyTextList()
	{
		// Check if the Empty ListView Label Displayed
		App.Container.Resolve<HomePageViewModel>().
		    IsEmptyTextList.ShouldBe(true);
	}
}

So as you can see, we’re basically following a mix of ViewModel and UI Element objects to check for the requirement of each step in this code behind test code. Also I’ve taken the liberty to rename the parameter names such as “int itemCount” to my liking! 😉

One more thing you can notice is that, if you take a look at the HomePage.feature file, its Scenario steps will be highlighted in white color as follows, confirming that our Scenario Steps are now bound to C# code behind Step Definitions.

Aha! there you go, a happy happy feature file ready to go! 😀

So we created our HomePage Feature file and Steps files, and they’re sitting in harmony next to each other in our project. What’s next you ask?

As of now, if everything is set up properly, you should see your first Feature Scenario ready and executing in Test Runners without any issue! 😉

Let’s run it yo!

And it passes the test with beautiful green! lol 😀

Yes, more Scenarios!

Yes, like I mentioned before, you can add any number of of Scenarios in a given Feature, so let’s go ahead and add more scenarios to the HomePage Feature!

Feature: HomePage

Scenario: App Launching First Time Test
          ...

Scenario: Navigating to New Text Page Test
          Given I have launched the app
          Then I am in the Home Page
          And I click on "New Text" Button
          Then I am in the New Text Page
        
Scenario: Deleting Text Item Text
          ...

Simply a matter of following the same pattern, and binding to the Step definitions behind in code behind! Go crazy! 😉

Clean up with Sharing…

Now let’s take it up a notch, by sharing our Step Definitions, which will certainly increase the reusability of our test code and reduce repetition. SpecFlow uniquely facilitates this feature where, any given Step Definition is shared and accessible across the same namespace.

Let’s create a new class, SharedSteps.cs which will be used to hold all our common shared step definitions…

[Binding]
public class SharedSteps
{
	public TestApp App => TestHooks.App;

	[Given(@"I have launched the app")]
	public void GivenIHaveLaunchedApp()
	{
		...
	}
	
	[Then(@"I am in the ""(.*)"" Page")]
	public void ThenIAmOnThePage(string pageName)
	{
		...
	}
	
	...
}

We need to add the [Binding] attribute to mark the class for SpecFlow bindings, and then we include all the step definitions we need to share across all our Features under the same Test environment.

Passing Arguments…

As you noticed before, we can pass any number of arguments or parameters in a given step, as either integer or string values. If it’s an integer parameter you can directly pass it as is in the step, but if you want to pass a string parameter, then you need to surround it with upper quotes as shown below…

Scenario: Creating new Text Item Test
          ...
          Then I am in the "Home" Page
          And I can see 0 Items in Text List
          ...
          Then I am in the "NewText" Page
          And I add New "Test Title 1" and "Test Description 1"
          ...

The above is handled in the code behind step definition as follows,

[Then(@"I am in the ""(.*)"" Page")]
public void ThenIAmOnThePage(string pageName)
{
	...
}

[Then(@"I can see (.*) Items in Text List")]
public void ThenICanSeeTextItemInListView(int itemCount)
{
	...
}

[Then(@"I add New ""(.*)"" and ""(.*)""")]
public void ThenIAddNewAnd(string textTitle, string text)
{
	...
}

There you go pretty neat eh! but let’s take it up a notch, where what if we need to pass multiple values for each parameter in the step? Now that’s where Scenario Outline comes to rescue,

Scenario Outline: Creating new Text Item Test
                  ...
                  And I add New "<TextTitle>" and "<Text>"
                  ...

Examples: 
	| TextTitle    | Text               |
	| Test Title 1 | Test Description 1 |
	| Test Title 2 | Test Description 2 |
	| Test Title 3 | Test Description 3 |

Using a Scenario Outline, you can simply provide multiple values for each parameter in the Example table. You can see in the above example, where I’m passing the parameters “TextTitle” and “Text” with multiple values into the Scenario. SpecFlow will handle this during test runtime as separate scenario executions with the dataset in each row. Clever trick! 😉

SpecFlow blog has a full fledge post on this, which I highly recommend you take a look: https://specflow.org/2019/improving-gherkin-specs-with-specflow-step-argument-transformations/

Just like that, SpecFlow is full of awesome features you can utilize build your Tests! 😀

Mock em!

Hence we’re using  Xamrin.Forms.Mock, it should be able to handle all the Xamarin.Forms related behaviors and functionality in our Test environment directly, such as Navigation, UI Elements rendering and so on. If you have any platform specific features, then you need to mock those service instances in your testing environment.

I’ve one a similar case here in my demo with the ILocationService, which has a MockLocationService implementation in the Test environment.

If you need to mock any sample fake data, then you could use an awesome library like moq or any other alternative such as, Faker.net and Bogus which are also popular!

In a scenario where, you have actual API calls going in or out of your app, you shouldn’t use them in your test run time. You need to create mocked Services for those API bound calls, with fake data sets attached to them, as the standard practice for Testing.

Finalizing…

So all of this awesomeness is committed into my github repo:

Github repo:
github.com/UdaraAlwis/XFWithSpecFlow

Since I took the Page based pattern for organising my SpecFlow tests, here’s the set of Features I ended up creating. Each Feature has its own Steps Definition class alongside them. There are multiple Scenarios in each Feature.

Under the Test folder I’ve placed all my SpecFlow Features, but you can restructure this hierarchy as you please, even include your own sub folders containing different sets of Features as well… 😉

You can see the SharedSteps class that I extracted for maintaining shared step definitions. So to sum it up, in my demo below are the SpecFlow Features that represents each page…

  • Home Page : HomePageFeature
    • Scenario: App Launching First Time Test
    • Scenario: Navigating to New Text Page Test
    • Scenario: Deleting Text Item Text
    • Scenario: Data Persistence Test
  • New Text Page: NewTextPageFeature
    • Scenario: Navigating to New Text Page Test
    • Scenario Outline: Creating new Text Item Test
    • Scenario: Validating Input Data Test
  • View Text Page: ViewTextPageFeature
    • Scenario: Navigating to View Text Page Test
    • Scenario: View Text Details and go back Test

Maintaining a good readability of your Feature Scenarios can definitely benefit you in the long run! 😉

So with that, once you open up your Test Runner, either built in Visual Studio Test Runner or even a 3rd Part Tool like ReSharper Test Runner, all your tests should be discoverable as below…

All the SpecFlow Features are shown with all the Test Scenarios in them, ready to be executed! 😉

Demo Time!

So let’s fire up these UnitTests…

Woah! What a satisfying thing to watch eh! 😀 One of the best things about it is that, we can see each executed step in detail as human-friendly text. SpecFlow FTW!

Github repo:
github.com/UdaraAlwis/XFWithSpecFlow

Once again feel free to grab it on my github! 😉

SpecFlow mindset…

Integrating SpecFlow based Tests in our Xamarin.Form projects brings all the stakeholders together, by promoting Human friendly test language as living documentation.

This is how We do it – Defining these Features and Scenario Steps require a certain mindset, where we need to look at our application or software in an End User’s perspective. You can integrate SpecFlow as a form of Test Driven Development as well, which is what we’re doing at our company, where we extract the Features, Scenarios and their Steps based on the Requirement Specification, and we start building the Application from there on wards.

Perspective of the End User – In the surface it might look quite easy and straightforward to define these test cases step by step, but sometimes it’s not quite the same for a technical person, due to the heavy technicality they’re focused on and they tend to forget the perspective of the end User. As I’ve experienced in my career, adopting this whole Behavior Driven Development paradigm might be confusing for a DEV personnel sometimes. That’s why sometimes its best to get involvement from a QA or BA personnel in the whole preparation process.

Take it easy yo! – In my personal experience, its best to take it easy! Do not over-complicate, over-exaggerate or think in terms of technical aspect. Just think in the simplest of terms, of yourself as an end user, and look at the requirement that needs to be implemented as such. I too had to overcome this problem myself, since I was a long time developer and when I first tried to adopt myself into SpecFlow based testing, it was quite difficult, but eventually I got the hang of it.

Short and simple! – Keep it short and simple, and maintain clear separation between different steps. If you notice a certain step is getting too complicate or longer than usual, then break it down to several steps. The most important thing is to maintain simplicity, for anyone to easily read and understand.

It’s actually Fun! – It might seem like too much work in the beginning, but trust me, once you get the hang of it, its actually fun. It makes total sense to maintain behavior driven development practices with human-readable testing with all stakeholders of the project!

Conclusion!

SpecFlow brings the whole paradigm of Behavior Driven Development for .NET development, where by helping teams bind automation to feature files and share the resulting examples as Living Documentation across the team and stakeholders. You can easily adopt SpecFlow into Xamarin.Forms projects just the same as any other Testing Framework! SpecFlow provides a whole bunch of amazing features for facilitating these great testing capabilities, but I’ve only touched the tip of the ice berg in this article. Please explore more at: https://specflow.org/

Hope this documentation out of my own experience helps any of you fellow Xamarin.Forms devs out there! Share the love! 😀 Cheers yol!

XAMVVM-02 TDD UnitTesting with Xamarin.Forms!

Thinking of how to adopt Testing practices into your Xamarin.Forms project, in this world of test driven software development? 😉 You’re about to find out!

Yes, you can easily incorporate UnitTest cases into your Xamarin.Forms project just like any other .NET solution, and there’s plenty of ways to do with several test frameworks.

As for the sake of clarity let me start off with a bit of basics…

Why UnitTesting?

So that we could write better software, with minimum failure rate. Specially for the continuous development of the software, making sure today’s code logic change doesn’t break any other elements of the application the next day, to simply put.

UnitTesting is a great approach for Test Driven Development based software building, where we test our code from the smallest units we could break into, making sure top to bottom all the bits are executing as expected! 😉

Follow a pattern…

It’s best to keep your UnitTest cases organised and categorised, as it could get messy when your Application grows as well as your test code base. You can organise your test cases according to a certain pattern, either based on your Application Pages or Flows.

Using Page based pattern for organising our test cases, allows us to write the test cases as they originates from each Page context itself. Further more on the base of behavior and functionalities available in each page in the application, as an example Home Page, Shopping Cart Page, Payment Page, and etc…

You could also use a Flow based pattern for your test cases, where you write test cases accordingly each individual feature flow of the application, as an example Login Flow, Order Flow, Payment Flow, and etc…

The choice is up to your requirement and the nature and complexity of your app. Although in my opinion page based approach could be easy to manage the test cases in long run.

Xamarin.Forms and UnitTesting!

Basically we could use any .NET Testing framework to test our Xamarin.Forms projects such as following.

  • MsTest
  • NUnit
  • xUnit, etc…

There are mainly two approaches we could take for UnitTesting our Xamarin.Forms project…

– ViewModel instances testing: This is about creating instances of the ViewModels of the app inside our UnitTest environment and testing each execution flow.

– Runtime Mocked testing: Here we’re creating a mocked app run time using a third party library inside our UnitTest environment and testing each execution flow.

ViewModel based testing, is a very limited form of testing hence there’s no way to perform testing on Navigation and UI Interactions flows. Although this is very easy to implement, it is not very effective, since with Xamarin.Forms applications we’re dealing with user interactions and all. Runtime Mocked testing is actually a much better way, hence we get to go through the actual application UI flow for each our test cases. So let’s do that! 😉

Xamarin.Forms Runtime Mocked UnitTesting!

Like I said above, this is the most effective since it not only saves a lot of development time, but also beneficial for TDD practices for accelerating development.

So we need to mock the Xamarin.Forms runtime without actually launch the app in an emulator or a device, which is going to be done using this awesome library, Xamarin.Forms.Mocks! Allowing us to create an actual instance of the app in memory, mocking the whole Xamarin.Forms run-time, allowing us to navigate through the app as if we’ve actually launched the app.

How to?

First thing we need to create a new UnitTest project in our Xamarin.Forms solution. Then add a reference of our Xamarin.Forms .Net Standard project to it, so that we can instantiate the app and add references from it into our test project. Next we have to add Xamarin.Forms.Mocks, nuget to the test project to emulate the Xamarin.Forms run-time. 😀

Finally, you can straight up create an instance of App class and access your Xamarin.Forms project’s objects in runtime!

But if you’re using a 3rd party MVVM framework like Prism, they usually have their own Container registration, which we need to manually handle ourselves in a mocked run-time environment. On the bright side, it also gives us more flexibility of control, since we could register our own mocked services for Test environment, such as a Location Service! whereas we could return a mocked fake location data when we override the LocationService with our own FakeLocationService. 😉

Here we override the default App class in our Test project with necessary container registrations and store it in a singleton static object, so that we can access it anywhere in our test environment. Oh and alongside we’re initiating our Xamarin.Forms Mocks run-time as well!

Now its all ready to go! Pretty straight forward eh! let’s get down to business.. 😉

Hands on time!

So just to showcase this hands-on awesomeness, I’ve prepared a simple Xamarin.Forms project application, where you can create simple notes, attach location data, attach created date time values and store them locally, allowing you to view them at any time in a list of items. Quite a simple text-pad-like app.

I’ve named this project solution as, XFTextpadApp and it uses Prism as the MVVM framework.

As you can see above is a view of the project structure with the complete MVVM set up. Let me also share a bit of showcasing of the app and its features to give a more in depth context.

Here’s a little peek into features of this demo Xamarin.Forms Textpad app running on iOS!

In the Home page you can view the List of Texts you have saved. By clicking on a Text item in the Home page list you can view that Text item in detail in the View Text page. Then once you click the “New Text” Button it will take you to the New Text page where you can create and save new Texts…

In the New Text page you can create new Texts with a Title and Description of your Text and click “Save” button to save it with the Location and Time data attached to it.

Then you will be navigated back to Home page. In the Home page Text list you can delete saved Text by using the context menu as well…

Thanks to Xamarin.Forms we can deploy it directly to iOS, Android, and UWP as well! 😉

Now the App project is ready, we need to add Test project to it.

Let’s begin by adding the Test project to our Xamarin.Forms project, create a new folder in the solution, named as “Tests” and then right click on it -> Add -> Add New Project

Now this is where the choice is absolutely up to you, as to which testing framework to choose from. Just for this demo, I’m gonna use NUnit Test framework, hence I will select NUnit Test Project (.NET Core) template and create our test project…

I will be naming the test project as, XFTextpadApp.NUnitTests making sure to stick to the standard naming practices! You might want to pay some attention to the Project Path there as well, where as to make sure we set the path to be inside the “Tests” folder that we created earlier.

First thing first, add a reference of the host XFTextpadApp .NET standard project into our XFTextpadApp.NUnitTests project. Then we’re going to add our Xamarin.Forms Mocking library, Xamarin.Forms.Mocks.

Just to make sure we write some beautiful test code, let’s add Shouldly nuget as well. This is more of a personal choice 😉 or if you prefer you could use the default assertions of NUnit (NUnit.Framework.Assert), or which ever the test framework you have chosen to set up.

If all went well then you should see the references as above. Now that’s out of the way, next on let’s get into coding!

Create app instance…

You could directly use the existing App class instance inherited from the Xamarin.Forms project within our Test project environment, but in the case of using 3rd party MVVM frameworks, or even when you want to mock some test compatible services, such as a GPS location service!?, then you need to construct your own App instance that’s catered for the Test environment. Which is what we’re going to do in this step.

Something to note here is that, the way you construct your Test App instance is completely dependent on how you have constructed your Xamarin.Forms application, so try to duplicate it as much as possible.

Let’s start by creating the instance of our app for the test environment. This basically means we need to create App class’s instance with all the container registrations set up, similar to what we already have in our App.xaml.cs file. Let create a new class called TestApp in our XFTextpadApp.NUnitTest project root.

public class TestApp : PrismApplication
{
	public TestApp() : this(null) { }

	public TestApp(IPlatformInitializer initializer) : base(initializer) { }

	protected override async void OnInitialized()
	{
		...
		
		await NavigationService.NavigateAsync("NavigationPage/HomePage");
	}

	protected override void RegisterTypes(IContainerRegistry containerRegistry)
	{
		containerRegistry.RegisterForNavigation<HomePage>();
		...

		containerRegistry.GetContainer().RegisterType<HomePageViewModel>(new Unity.Lifetime.ContainerControlledLifetimeManager());
		...
	}
}

Now make sure to register your Pages, ViewModels and Services accordingly. Also notice that how I have set up the default start up navigation in the OnInitialized() method according to Prism.

Next the Hooks…

This is more like the helper class that we’ll be using to set up the necessary hooks for our test run time environment, such as instantiating the App instance object, and initialising MockForms. Here we’re going to keep a public static object of our App instance, which we will be using all across out tests cases. Let’s create a class called TestHooks

public class TestHooks
{
	public static TestApp App { get; private set; }

	[SetUp]
	public static void Setup()
	{
		Xamarin.Forms.Mocks.MockForms.Init();

		App = new TestApp();
	}

	[Test]
	public static void IsAppRunning()
	{
		Assert.NotNull(App);
	}
}

We’re using the [Setup] attribute of the NUnit framework to do the initiation of the App instance before each execution of tests. And we’re also adding a simple test in the same class to make sure the instantiation has happened properly without an issue, as you can see by the method IsAppRunning() which is decorated with the [Test] attribute of NUnit. We’ve made those hooking methods static because we are going to be accessing them in our test cases!

And since we have just added our first Test case, we could try and run it, where as if everything is set up properly, you should see your app instantiating well and our first test case is passing! 😉

And it all passes the test with green! lol 😀

If you can’t get this step to pass successfully, then there’s definitely something wrong with the Test App instance set up, so you might wanna look into the DI Container initialization and all.

Alright, but we’re not done yet!

One base for all…

Then we are one step away from creating our Test cases! 😀 so before that we need to create the Base class for our Test classes that would be containing those Test cases. So let’s create out BaseTest class in the root of the project…

/// <summary>
/// Base class for Test classes
/// </summary>
public class BaseTest
{
    /// <summary>
    /// Instance of the app
    /// </summary>
    public static TestApp App { get; private set; }
 
	[SetUp]
	public void Setup()
	{
		TestHooks.Setup();

		App = TestHooks.App;
	}
     
    ...
}

It’s pretty simple, but its important to abstract a base layer for our test classes to dump all the repetitive test steps to reduce duplication of test code. Here we’re simply retaining the TestApp instance through the TestHooks class we just created before, and that instance will be useful for our Test cases later. 😉

On to the final step!

Creating the Tests…

Now that all is set up and ready to go, let’s create our actual Tests. But first create a “Test” folder in the root of our XFTextpadApp.NUnitTest project.

If everything is well set up until now, then it should look like the above structure.

Let’s add a new class to the Tests folder, but as for the name, you could use anything as you wish according to your preferred naming convention, but I would usually prefer something like “<PageName>Tests”, keeping the Page as the objective for the set of test cases. So let me create HomePageTests class, which will inherit from the BaseTest class.

Next we’re going to create the methods that actually indicates the Test cases, let’s take an example such as,

Scenario:
First time I launch the app
I am Navigated to the Home page
I see an empty list of data
I see a label indicating empty data

We could create the Test case for the above scenario as shown below…

[TestFixture]
public class HomePageTests : BaseTest
{
	/// <summary>
	/// Launching the app for the  first
	/// time and navigating in to Home page
	/// </summary>
	[Test]
	public void AppLaunchingFirstTimeTest()
	{
		// Test steps here
	}
}

As you can see I’ve named our test case method as, AppLaunchingFirstTimeTest, considering the gist of the test scenario that we’re targeting. In fact providing a proper name for your test cases are quite important, hence it makes it easier to read and understand, as well as for future maintenance.

Now Thanks to the Xamarin.Forms.Mock, we’re able to pull objects from Xamarin.Forms UI elements and the DI Container to construct a perfect test case for any given scenario. You can access any Xamarin.Forms elements through the App object as usual to check for any values you require.

So with that in mind, let’s write the Test steps for our test case..

[Test]
public void AppLaunchingFirstTimeTest()
{
	// Is the app running
	App.ShouldNotBeNull();
	
	// Retrieve Navigation Stack
	var navigationStack = ((NavigationPage)App.MainPage).Navigation.NavigationStack;
	
	// Am I in the Home page
	navigationStack.Last().BindingContext.GetType().Name.ShouldBe(nameof(HomePageViewModel));

	// ListView should be empty
	App.Container.Resolve<HomePageViewModel>().TextList.Count.ShouldBe(0);

	// Empty ListView Label Displayed
	App.Container.Resolve<HomePageViewModel>().IsEmptyTextList.ShouldBe(true);
}

Let me explain step by step…

First thing we need to do is to make sure the App is running, so in our Test case, let’s access the TestApp instance in our BastTest class, and use Shoudly’s extension to check for null or not state.

Then we access the Navigation stack through the App’s Navigation object, which we’re going to check for the current active Page, through the BindingContext type as you can see.

Finally we check if the ListView is empty by accessing the TextList collection object inside the Homepage ViewModel and we do the same for checking if the Empty list indicator label is visible as well. 😉

There you go, you’ve just created your first UnitTest case for your Xamarin.Forms app!

Mixing it up!

Since our Xamarin.Forms runtime is mocked, you can mix and mingle among the actual UI Elements of your App and DI Container objects.

You see in the previous demo code, how I’ve accessed NavigationStack of the app using App.MainPage instance, as well as you can see how I’m using the Current active Page instance to access its child element, which is a Label element and check its rendered value as follows…

// Get the value in ViewModel
var viewingTextItem = 
   App.Container.Resolve
      <ViewTextPageViewModel>().TextItem;

// Check TextTitle Label value
var textTitleLabel = 
((Label)((Grid)
	((ViewTextPage)GetCurrentPage())
		  .Content).Children.First());
textTitleLabel.Text.ShouldBe(viewingTextItem.TextTitle);

You can see how I have retrieved the Label element by traversing through the Page object, and comparing the results with the value I’ve retrieved from the ViewModel object. So you can mix and match these two approaches in harmony for implementing complicated test cases easily!

App Properties…

Thanks to the mocked Xamarin.Forms runtime we’re able to access most of its functionality as it is in our test cases, which goes to the Application Properties as well.

As an example here I am clearing out my Application Properties on TearDown event after any given test case is executed.

// Clear App properties in memory
Application.Current.Properties.Clear();
await Application.Current.SavePropertiesAsync();

Navigation…

The Navigation in my demo project is handled by Prism, which uses the default Xamarin.Forms navigation underneath it. The Xamrin.Forms.Mock seem to be handling it pretty well as well. So you wouldn’t be need to do any special handles in the test code.

[Test]
public void NavigatingToNewTextPageTest()
{
	...

	// Navigating to New Text page
	App.Container.Resolve<HomePageViewModel>()
		.GoToNewTextPageCommand.Execute();

	// Am I in the New Text page
	GetCurrentPage().BindingContext.GetType()
		.Name.ShouldBe(nameof(NewTextPageViewModel));
}

Hence I could simply call up the usual Navigation Commands that I use on the Button element, here in my unit test code as well. 😉 Navigation will behave as expected!

Mockin’ Services!

Like I mentioned before if you have a Service which relies on platform specific features, then you need to mock those services instances in your testing environment. In my demo I’m using a LocationService, which I have mocked in the my test code as follows…

/// <summary>
/// Mocked Location Service
/// </summary>
public class MockLocationService : ILocationService
{
	public Task<Location> GetLocation()
	{
		// Mock location data
		return Task.FromResult(new Location(0.11111, 0.22222));
	}
}

Also do not forget registration in the TestApp instance which I showed before…

// register mocked ILocationService
containerRegistry.RegisterSingleton
      <ILocationService, MockLocationService>();

Now with that, every time the actual App code try to resolve the LocationService it will get the MockedLocationService object and use its mock data during the test executions. You could also use an awesome library like moq for mocking services and data as well.

Fake em!

If you have actual API calls going in or out of your app, you shouldn’t use them in your unit tests, hence it could cause for slowing down the test executions, and would consume a lot of resources, keeping in mind tests are meant to be executed repeatedly.

So you need to create Mocked Services for those API bound calls, with fake data sets attached to them, so in test code, they would be using the fake data or fake responses instead. 😉 Another reason to use moq library! There are others as well, Faker.net and Bogus are also popular!

Reduce the repetition!

There could be repetitive steps in these Unit Test cases, therefore you can improve the code by extracting out those common repetitive test steps into separate methods or extensions.

public class ViewTextPageTests : BaseTest
{
	[Test]
	public void NavigatingToViewTextPageTest()
	{
		...
		// Create a new Text item
		var textItem = CreateSampleTextItem();
		...
	}

	[Test]
	public void ViewTextDetailsAndGoBackPageTest()
	{
		...
		// Create a new Text item
		var textItem = CreateSampleTextItem();
		...
	}

	public TextItem CreateSampleTextItem()
	{ ... }
}

As an example in both my test cases above, I need to create a new TextItem object, hence I’ve extracted it out to a common method which is used in both, reducing the repetition.

Here’s another example where I’ve created the following helpers in BaseTest class,

/// <summary>
/// Returns the active Page
/// </summary>
/// <returns></returns>
public static Page GetCurrentPage()
{
	var navigationStack = ((NavigationPage)App.MainPage).Navigation.NavigationStack;
	return (Page)navigationStack.Last();
}

/// <summary>
/// Returns the active ViewModel
/// </summary>
/// <returns></returns>
public static ViewModelBase GetCurrentViewModel()
{
	var navigationStack = ((NavigationPage)App.MainPage).Navigation.NavigationStack;
	return (ViewModelBase)navigationStack.Last().BindingContext;
}

Allowing me to retrieve the current active Page or the ViewModel directly.

Before and After Test Case…

Most Testing frameworks provides you with Before and After hooks for a given Test Case, where as in my demo, NUnit provides [Setup] and [TearDown] subsequently.

public class BaseTest
{
	[SetUp]
	public void Setup()
	{
		// Set up steps
	}
	
	[TearDown]
	public async Task TearDown()
	{
		// Teardown steps
	}
     
    ...
}

As I’ve shared before I’ve set up the [Setup] attribute in the BaseTest class, allowing me to reinstantiate TestApp instance before each Test Case executes.

[TestFixture]
public class HomePageTests : BaseTest
{
	[SetUp]
	public new void Setup()
	{
		// Page specific Setup
	}

	...
}

You can override the set up in your Page specific test class and set up the required customized setting up as well. This was you can also share data across the whole flow of the page test scope without resetting the TestApp instance. Quite a handy trick to keep in mind! 😉

Finalizing…

So all of this awesomeness is committed into my github repo:

Github repo:
github.com/UdaraAlwis/XFWithUnitTest

Since I took the Page based pattern for organising my unit test cases, here’s the set of test classes I ended up creating for each page.

Under the Test folder I’ve placed all my test class, but you can restructure this hierarchy as you please, even have sub folders containing different sets of test as well… 😉

So in my demo below are the test classes that represents each page…

  • Home Page : HomePageTests
  • New Text Page: NewTextPageTests
  • View Text Page: ViewTextPageTests

Maintaining a good readability of your test cases can definitely benefit you in the long run! 😉

Once you open up your Test Runner, either built in Visual Studio Test Runner or even a 3rd Part Tool like Resharper Test Runner, all your tests should be discoverable as below…

All the UnitTest classes are shown with all the test cases in them, ready to be executed! 😉

Demo time!

So let’s fire up these UnitTests…

Woah! What a satisfying thing to watch eh! 😀

Github repo:
github.com/UdaraAlwis/XFWithUnitTest

Once again feel free to grab it on my github! 😉

Conclusion

You can easily implement UnitTesting in Xamarin.Forms just like any other .NET project, and there are plenty of ways to do it. Mocking Xamarin.Forms runtime and implementing our UnitTests on top of that, is a great way to ensure that our tests are executing as close as it gets to the real app runtime. You can easily integrate Xamarin.Forms.Mocks library with pure Xamarin.Forms or along side any other MVVM Library to set up your UnitTests!

We need to make sure to follow best practices and maintain clean, easy to read, test code across all our UnitTesting implementations. You can take different approaches to organising your test cases, while I personally believe Page-Context based pattern provides more clarity.

 Hope this documentation out of my own experience helps any of you fellow Xamarin.Forms devs out there! Share the love! 😀 Cheers yol!

Playing Audio with the MediaManager Plugin for Xamarin.Forms!

Let me show you how to play Audio in Xamarin.Forms across Android, iOS and Windows UWP using the super easy plug and play MediaManager Plugin.

So you wanna play Audio in your Xamarin.Forms app? Stream an audio file over the internet or stored locally in your device Gallery? Listening to songs or podcasts even when the app is in background mode or device is locked away? Then you’re in the right place! 😉

So playing audio in a music player style sounds like a complete nightmare for a cross-platform framework like Xamarin.Forms, but thanks to this incredible MediaManager plugin, just a breeze of work to deploy across Android, iOS and Windows UWP environments.

MediaManager Plugin!

Long time back I remember reading up the article in Xamarin Blog, Play Audio and Video with the MediaManager Plugin for Xamarin, https://devblogs.microsoft.com/xamarin/play-audio-and-video-with-the-mediamanager-plugin-for-xamarin/

Back then, I remember there were no direct support for Xamarin.Forms itself, but now we do, with simple plug and play capabilities in this MediaManager Plugin!

Github:
github.com/Baseflow/XamarinMediaManager
Nuget:
nuget.org/packages/Plugin.MediaManager/

Please feel free to take a look at their official github page, and the implementation code if you’re interested in digging down deep.

Backstory…

I was lucky enough to stumble upon the opportunity to explore the implementation of Audio playback in one of the Xamarin.Forms project I’m working on recently. The core feature of that app was to play audio sources that are stored online, with continuous app background playback enabled, similar to a music player or podcast player.

The first thing came to my mind was the MediaManager plugin. So I tried it out following the Github page and the Xamarin blog article.

But unfortunately I came across a lot of issues, trying to set up in a fresh Xamarin.Forms project itself, even though I followed the steps to the detail. So I had to scrape through old forums and sample projects off of Github, for a series of trial and error, figuring out the proper set up.

It turns out all the articles and documented setup guidelines are mostly outdated, and the Plugin has gone through so much new changes and improvements over the years. So I thought of sharing my experience on setting up the MediaManager Plugin for Xamarin.Forms, step by step from scratch! 😉

Sneak Peek!

Let me share a little sneak peek into the cute little demo I built…

That’s the beauty with a whole bunch of awesome features powered by MediaManager Plugin!

I’ve published this whole awesome demo up in my github repo,

Github repo:
github.com/UdaraAlwis/XFAudioPlayer

Feel free to take a look for a headstart before we begin! 😉

Setting it up!

Let’s begin with the set up of the Plugin with your Xamarin.Forms project. So I’m going to be using a fresh out of the box Xamarin.Forms project with the version 1.5.3.2, which is the latest updated version as of now.

Open up the Nuget Package Manager, on the Solution node, and search for Plugin.MediaManager.Forms package, and make sure to install it on your .NET Standard project node only, as shown below.

As of the writing of the blog post, I would recommend sticking to v6.94 version of the plugin as you can see above. The latest version had given me some run time issues.

It is important that you install the plugin only in the .NET Standard project, hence we’re using the Xamarin.Forms related package of the MediaManager plugin.

Also you may have noticed, there are multiple other packages related to MediaManager plugin, which caters for different purposes such as Plugin.MediaManager for Xamarin Native, Plugin.MediaManager.Reactive for Reactive Extensions, Plugin.MediaManager.ExoPlayer for ExoPlayer based implementations and so on.

Feel free to play around with them if you ever come across the need for such. Next we need to configure the initiation of the plugin.

No initiation setup required in platform projects, but in the App.xaml.cs of your Xamarin.Forms project node,

public partial class App : Application
{
	public App()
	{
		InitializeComponent();

		CrossMediaManager.Current.Init();

		MainPage = new NavigationPage(new MainPage());
	}
}

Oki doki, you’re good go!

Let the coding begin!

It’s actually easy to use Plugin.MediaManager in Xamarin.Forms! It provides a Singleton access to the complete player plugin instance, CrossMediaManager.Current, so you get full control of all the properties, behaviours and features in one place across the entire app context.

First, Play Audio!

Just hit the Play() for your audio as simple as below…

var audioUrl = "https://ia800605.us.archive.org/32/items/Mp3Playlist_555/Daughtry-Homeacoustic.mp3";
await CrossMediaManager.Current.Play(audioUrl);

Yes! it’s that simple. Check here the full list of Play() method overrides available: https://github.com/Baseflow/XamarinMediaManager#other-play-possibilities

Player Features!

Any Audio player should have the basic features such as Auto Play, Shuffle, Repeat mode and so on yeah? 😉

CrossMediaManager.Current.ShuffleMode = ShuffleMode.All;
CrossMediaManager.Current.PlayNextOnFailed = true;
CrossMediaManager.Current.RepeatMode = RepeatMode.All;
CrossMediaManager.Current.AutoPlay = true;

CrossMediaManager.Current instance provides you direct access to all those features you need.

Play, Pause, Stop, Resume?!?

Yeah well those key features of are easily accessible, and then some! 😉

var result = await CrossMediaManager.Current.Play();
var result = await CrossMediaManager.Current.Pause();
var result = await CrossMediaManager.Current.Stop();

All those returns a bool indicating the results of the action.

var result = await CrossMediaManager.Current.PlayPrevious();
var result = await CrossMediaManager.Current.PlayNext();

How about if it’s playing, then pause, it its pause, then resume play?

await CrossMediaManager.Current.PlayPause(); 

Yeah it’s got a feature for that too! 😀 which I’ve also used in my demo.

Step and Seek!

Yep, not hide and seek for sure…

// step forward or backwards
await CrossMediaManager.Current.StepForward();
await CrossMediaManager.Current.StepBackward();  

// seek to a specific position          
await CrossMediaManager.Current.SeekTo(timespan);

You can even adjust the default value for stepping actions using, CrossMediaManager.Current.StepSize and then directly seek to a specific location of the audio using SeekTo with a TimeSpan value! 😉

Access Media data…

You can load the metadata or media details of the audio source as follows,

IMediaItem currentMediaItem = await 
         CrossMediaManager.Current.Play(audioUrl);

Whenever you call Play() method it will return IMediaItem object which contains all the metadata regarding the audio source, such as Title, Artist, Album, Year, and etc…

Sometimes the retrieval of the metadata could take a while depending on the media source or the run time platform, so you can subscribe to the MetadataUpdated event to retrieve the data once they’re extracted.

var mediaItem = await CrossMediaManager.Current.Play(audioUrl);
mediaItem.MetadataUpdated += (sender, args) => {
	var title = args.MediaItem.Title;
};

This might be a bit troublesome, subscribing and unsubscribing, so you could access the metadata from the Queue instance directly, CrossMediaManager.Current.Queue.Current

IMediaItem currentAudioItem
       = CrossMediaManager.Current.Queue.Current;

Or directly as follows..

var title = CrossMediaManager.Current.Queue.Current.Title;
var artist = CrossMediaManager.Current.Queue.Current.Artist;
var album = CrossMediaManager.Current.Queue.Current.Album;
...

You can bind your UI properties to these values, once you execute Play() on your audio.

Now that I mentioned Queue, let’s get into that next…

Queue it up!

MediaManager simplifies a whole bunch features for you, and one of them is the Queue, which you can access directly through the instance, CrossMediaManager.Current.Queue which provides the IMediaQueue object. This one carries a whole bunch of awesomeness that you can use for your own player.

var currentMediaItem 
          = CrossMediaManager.Current.Queue.Current;
var nextMediaItem 
          = CrossMediaManager.Current.Queue.Next;
var previousMediaItem 
          = CrossMediaManager.Current.Queue.Previous;

In my demo I’m using the the override of passing a List of media urls to be played in a queue,

var songList = new List<string>() {
	"https://files.freemusicarchive.org/storage-freemusicarchive-org/music/no_curator/Yung_Kartz/July_2019/Yung_Kartz_-_02_-_Levels.mp3",
	"https://files.freemusicarchive.org/storage-freemusicarchive-org/music/Creative_Commons/Ketsa/Raising_Frequency/Ketsa_-_08_-_Multiverse.mp3",
	...
};

var currentMediaItem = 
	await CrossMediaManager.Current.Play(songList);

I could easily access it using the CrossMediaManager.Current.Queue.MediaItems

ObservableCollection<IMediaItem> mediaItemsInQueue 
	= CrossMediaManager.Current.Queue.MediaItems;

It returns an ObservableCollection of the MediaItems that I have queued up.

var mediaItem =
	CrossMediaManager.Current.Queue[index];

Just like that you could retrieve a specific item from the Queue as well.

Add to Queue…

To add an item directly to the Queue using the Queue.Add() method but, you need MediaItem object of that audio source. You can use the MediaExtractor object to create the MediaItem object you require and add that to the Queue as follows…

var generatedMediaItem =
	await CrossMediaManager.Current
	.Extractor.CreateMediaItem(mediaUrl);
	
CrossMediaManager.Current.Queue.Add(generatedMediaItem);

Now that new audio source will be added to the bottom of the Queue waiting to be played..

Play from Queue…

Use PlayQueueItem() to play an item from the Queue…

// from index
var isSuccess = 
     await CrossMediaManager.Current.PlayQueueItem(index);

// pass in the MediaItem
var isSuccess = 
      await CrossMediaManager.Current.PlayQueueItem(mediaItem);

Or better yet, pass in the MediaItem itself from the queue, it will return a bool whether it was found in the queue and started playing or not.

Player State matters!

You might say, Play this, Play that, but how do you know if it’s actually playing or not? even before that is it still loading the media source? or still buffering the data?

You can easily monitor this by subscribing to StateChanged event,

CrossMediaManager.Current.StateChanged += Current_OnStateChanged;
...

private void Current_OnStateChanged(object sender, StateChangedEventArgs e)
{
	if (e.State == MediaPlayerState.Playing)
	{
		// playing mode
	}
}

MediaPlayerState enum provides us 6 states of the media playback,

  • Loading
  • Buffering
  • Failed
  • Playing
  • Paused
  • Stopped

You could also check the state suing extension methods,

var result = CrossMediaManager.Current.IsPlaying();
var result = CrossMediaManager.Current.IsBuffering();
var result = CrossMediaManager.Current.IsStopped();

These nifty little extensions returns a boolean value with regards to the state.

Better yet you also got a singleton property you can bind to,

MediaPlayerState state = CrossMediaManager.Current.State;
if (state == MediaPlayerState.Playing)
{
	// playing mode
}

Yep multiple flexible ways! 😉 There’s another useful extension method, CrossMediaManager.Current.IsPrepared() which allows you check if the Player is already set up with Audio sources, and is running.

In my demo app I use this in the home page where I need to make sure the Player instance is already initialised or not with audio sources every time I activate the app from background.

protected override async void OnAppearing()
{
	base.OnAppearing();

	if (!CrossMediaManager.Current.IsPrepared())
	{
		await InitPlay();
	}
}

Pretty handy!

Useful Events…

There are plenty useful events you can subscribe to in order to monitor different properties and behaviors, https://github.com/Baseflow/XamarinMediaManager#hook-into-events

CrossMediaManager.Current.StateChanged
	+= Current_OnStateChanged;
CrossMediaManager.Current.PositionChanged
	+= Current_PositionChanged;
CrossMediaManager.Current.MediaItemChanged
	+= Current_MediaItemChanged;

I for one am subscribing to these events in my demo app, for monitoring Player State changes, current Media playback Position changes, current MediaItem Change. These events provides specific types of EventArgs parameters which you can use in the event methods.

Keep track of Time!

It’s important to keep track of the playback time data such as, Position and Duration of the audio that you’re playing. In my demo I use the PositionChanged event and Position, Duration properties to update the UI accordingly to show the user playback time data.

TimeSpan currentMediaPosition
	= CrossMediaManager.Current.Position;
TimeSpan currentMediaDuration
	= CrossMediaManager.Current.Duration;

Here’s how I update some of the UI elements based on the Position and Duration changes..

var formattingPattern = @"hh\:mm\:ss";
if (CrossMediaManager.Current.Duration.Hours <= 0)
	formattingPattern = @"mm\:ss";

var fullLengthString =
	CrossMediaManager.Current.Duration.ToString(formattingPattern);
LabelPositionStatus.Text =
	$"{CrossMediaManager.Current.Position.ToString(formattingPattern)}/{fullLengthString}";

SliderSongPlayDisplay.Value =
	CrossMediaManager.Current.Position.Ticks;

All kinds of cool UI bits you could implement with those data! 😀

Loading Local Audio files..

Now this is a cool little feature I decided to implement. My demo app will be able to load local Audio files from the local file system, into the app, and play! 😉

This should work seamlessly across Android, iOS and UWP. So I’m going to be using another nifty little library called, FilePicker-Plugin-for-Xamarin-and-Windows, which will simplify the whole file picking set up much easier.

I need to allow only MP3 audio file types to be picked in the app, so let’s define that first,

string[] fileTypes = null;
if (Device.RuntimePlatform == Device.Android)
{
	fileTypes = new string[] { "audio/mpeg" };
}

if (Device.RuntimePlatform == Device.iOS)
{
	fileTypes = new string[] { "public.audio" };
}

if (Device.RuntimePlatform == Device.UWP)
{
	fileTypes = new string[] { ".mp3" };
}

So based on the platform we need to set appropriate filter values before we execute picking. Next let’s pick the file using our FilePicker library and load into our media queue…

var pickedFile = await CrossFilePicker.Current.PickFile(fileTypes);
if (pickedFile != null)
{
	var cachedFilePathName = Path.Combine(FileSystem.CacheDirectory, pickedFile.FileName);

	if (!File.Exists(cachedFilePathName))
		File.WriteAllBytes(cachedFilePathName, pickedFile.DataArray);

	if (File.Exists(cachedFilePathName))
	{
		// Create media item from file
		var generatedMediaItem =
			await CrossMediaManager.Current
			.Extractor.CreateMediaItem(cachedFilePathName);
		// Add media item to queue
		CrossMediaManager.Current.Queue.Add(generatedMediaItem);
	}
}

Once the user picks the file, we get the FileData object. I’m writing that file object to the app cache directory with the help of Xamarin.Essentials.FileSystem helpers.

It is better to load the file into memory from the cache directory hence some platforms could flag directly accessing files outside the app directories as a suspicious activity and eventually break the flow of the app.

Once we store the file safely in App Cache directory, we load it into our app, using the Extractor to create the IMediaItem object and pass it on to the MediaManager’s queue. 😉

Well that’s all the tidbits I got to share regarding the little demo I built!

Demo time!

So I built a simple demo audio player which will be playing MP3 audio sources stored online, and as an extra functionality, it will allow us to play locally stored MP3 files as well.

Github repo:
github.com/UdaraAlwis/XFAudioPlayer

The first page, which is the Home page, will host the main Audio Play feature, such as Play/Pause, Next, Previous and so on. Then another page which will display the current audio Queue loaded into the Player. The same page will have the functionality to load local MP3 files and add to the Queue on the go…

Let’s fire it up and see the magic! 😉

Here we got iOS working like a charm! Well I’m not able to showcase the background or lock screen activity since I’m running it on the iOS Simulator and I don’t have an actual iPhone 😛

Next we got Android, working marvelously… 😉 Here I’m showcasing the full length of features including continuous playback on app background state as well!

Here’s the good old UWP Windows, working like a breeze! App will continue playing even if the app is minimized or device is locked as expected for background playback state! 😀

Remember I told yol about the extra little feature I added, being able to load local Audio files!? here we have it, working like a charm across iOS, Android and UWP Windows…

Let me flex a little bit more on the continuous background audio playback… 😉

As you can see on Android, we got direct access to media playback while the app is on background mode, and the audio is still playing even on lock screen…

Then on UWP Windows runtime we got the same exact features, it even complies with device native media buttons on the laptop keyboard!

Oh also on Windows 10 lock screen at the bottom right corner… 😉

Woot! Woot! 😀

Issues…

Even though I managed to build this cool little demo, with the help of MediaManager Plugin, I did notice some issues with it.

On UWP Windows runtime, it wasn’t loading Audio meta data for sources which are stored online. As in for any internet audio source, it would not be able to load the meta data of it. I saw some issues raised in the github page regarding this. So for now, just during UWP run time, we should rely on manually loading the audio source metadata, hopefully until the issue is fixed. Although my guess is, it could be a Windows File system security restriction!?

Another issue is that on Android, if the app is killed manually while its in background, the audio playback will stop it self. Usually this shouldn’t happen as far as I’ve seen with other Audio player apps. There’s a pending issue logged in github for this as well.

Well that was pretty much it for the issues I noticed!

Conclusion

Well it was certainly fun little walk down the memory lane, apart from the trouble I had to go through following out of sync documentation. lol but it was worth it. It’s incredible how far MediaManager Plugin has come so far since the early days of Xamarin, and kudos to the developer @martijn00

MediaManager Plugin takes away all the pain of dealing with platform native handling of audio files and provide us direct access to great audio features. If you ever come across implementing an audio player app, this would be a great plugin to consider. Hope this little documentation of my experience with it was helpful for anyone out there! 🙂

Share the love! 😀 Cheers yol!

So I took up on TravelMonkey, the Xamarin + Cognitive Services Challenge!

Let me share my little adrenaline filled panic adventure into earning some awesome Xamarin Swag! from the Xamarin + Cognitive Challenge hosted by Microsoft, the TravelMonkey Challenge! 😀

Well it’s come to 2020, in the middle of a pandemic, a lock down, and it’s been a while since I took up on an actual challenge outside my work and personal coding experiments! Then I suddenly came across this little challenge posted by Microsoft, TravelMonkey – the Cognitive Services + Xamarin Combo Challenge! (https://devblogs.microsoft.com/xamarin/cognitive-services-xamarin-challenge/)

Backstory…

As usual, the first thing I checked, what’s in it for me, you know what I mean! 😉 YES! they had promised some awesome Microsoft swag! Xamarin t-shirts, monkeys, and stickers!?! Say no more, I was in! 😀 well at least I thought to myself… their Submission deadline was April 30, 2020 11:59 PM PDT!

The days went by, one by one, without even any second thoughts, yeah I’d do it tomorrow, or day after or some time… I’ll get it done!

Then suddenly, it was 29th April, the Friday night, oh shoot! tomorrow’s the deadline for submission of the awesome TravelMonkey challenge! Yeah well I could say it was my own procrastination that got me in that situation, I had waited till the last day!

Procrastination is bad!

Just like in that GTA San Andreas scene, in my head I was like, “Ah sh*t, here we go again!” it was literally a moment of panic, and I was the fence about giving it up. But then it was Friday night, the day I usually watch a good night movie and fall asleep to wake up very late on Saturday! 😦

But then again, it was middle of a pandemic lock down, and I haven’t really had this kind of a fun challenge in a while, so I thought of pulling an all nighter and getting it done! at least something worth while before the next 24 hours ended… 😮

At this point, I didn’t have a plan of what I’m going to be building or expand up on, so I thought of simply exploring the current implementation and figure out where are the points in which I could improve as for the challenge. Once again, it was a bad idea to start working on it, at a time when it was less than 24 hours before the submission! lol 😀

Sneak Peek!

But at the end, here the beauty I ended up building…

I know right.. gorgeous!

Yeah well behind all that eye-candy glamour there was a painful sleepless all-nighter experience, waiting to be unraveled…

Getting started…

So first, I forked the github repo from https://github.com/jfversluis/TravelMonkey into my own github repo: https://github.com/UdaraAlwis/TravelMonkey and set up the Azure Cognitive services in Free tier with the following,

  • Azure Computer Vision
  • Bing Translation
  • Bing Image Search

Then I got the API keys and hooked up into the Xamarin Mobile app project.

New Featurettes!

This is a travel related app! even though it is fictional. lol So I wanted to think of it as being used by smart Monkeys like us, who would love to see beautiful scenic photos of the top travel destinations in the world.

Why stop there? I should allow the users to search for a destination and view the top scenic photos of that destination, as a little cherry on top! 😉

Also how about letting the user translate any text into any language they choose? That would definitely come in handy for any traveller!

Bing Image Search FTW!

So I picked up the most visited destinations by international tourist arrivals data from Wikipedia, https://en.wikipedia.org/wiki/World_Tourism_rankings and hooked it up into the Bing Search Service to load images of those destinations. Each destination would be taken up with 10 images and we would randomize through them in the Home page carousel.

var client = new ImageSearchClient(
new Microsoft.Azure.CognitiveServices.Search.
ImageSearch.ApiKeyServiceClientCredentials(ApiKeys.BingImageSearch));

var imageResult = await client.Images.
SearchAsync(
	$"{destination} attractions", 
	minWidth: 500, 
	minHeight: 500, 
	imageType: "Photo", 
	license: "Public", 
	count: 10, 
	maxHeight: 1200, 
	maxWidth: 1200);

See how I modified the Bing Image search query there, {destination} attractions where as it would be executed as “France attractions”, “Thailand attractions”, and etc. So just like that I refined the search terms for scenic tourist photos from Bing Images.

Destination scenic Gallery!

I decided to add a travel destination Gallery page, consisting of scenic travel photos from Bing. User would be able to pick a destination from a presented list of countries in the Home page itself, and then navigate to its Gallery page to view the top 10 most scenic photos from Bing.

Here I did a little trick to load a list of countries in C# by tapping into CultureInfo object provided by .NET framework, pretty handy!

private static List<string> GetCountries()
{
	List<string> countryList = new List<string>();

	var getCultureInfo = CultureInfo.GetCultures(CultureTypes.SpecificCultures);

	foreach (var getCulture in getCultureInfo)
	{
		var regionInfo = new RegionInfo(getCulture.LCID);
		if (!countryList.Contains(regionInfo.EnglishName))
		{
			countryList.Add(regionInfo.EnglishName);
		}
	}

	return countryList;
}

This would return the list of countries in the world which I will be presenting to the user to choose from! I will use the Bing Image Search that I had already modified to load the scenic travel images set on the go.

Bing Translation FTW!

So I thought of adding some improvements to the Translation features, where currently they had a pre-set of languages they would translate to given the input text. I wanted to make it completely dynamic, by getting the list of languages available in Bing Translation service, and letting the user pick the languages they want to translate to.

Here’s how I got the list of supported languages Bing Translation,

public async Task<List<AvailableLanguage>> GetLanguageList() 
{
	string endpoint = ApiKeys.TranslationsEndpoint;
	string route = "/languages?api-version=3.0";

	using (var client = new HttpClient())
	using (var request = new HttpRequestMessage())
	{
		...
		request.RequestUri = new Uri(endpoint + route);
		// Send request, get response
		var response = client.SendAsync(request).Result;
		...
	}

	List<AvailableLanguage> availableLanguages = new List<AvailableLanguage>();
	foreach (var item in translationStatsResult.Translation)
	{ ... }
	return availableLanguages;
}

Once I got the available languages list, I would present them to the user to pick from for translating their input text. But during the app’s first time launch I would randomly pick 5 languages and show the translations.

So here’s how I extended the Translation service call with the dynamic request language list,

public async Task<List<AvailableTranslation>> 
TranslateText(string inputText, List<AvailableLanguage> listOfLanguages)
{
	// build the translate url chunk
	string requiredTranslationsString = "";
	foreach (var item in listOfLanguages)
	{
		requiredTranslationsString = requiredTranslationsString + $"&to={item.Key}";
	}
	
	...
	request.RequestUri = new Uri(ApiKeys.TranslationsEndpoint + "/translate?api-version=3.0" + requiredTranslationsString);
	... 
	
	translations.Add( new AvailableTranslation()
	{
		InputLanguage = bestResult.DetectedLanguage.Language,
		InputText = inputText,
		TranslatedLanguageKey = t.To,
		TranslatedLanguageText = t.Text,
		TranslatedLanguageName = MockDataStore.Languages.FirstOrDefault(x => x.Key == t.To).Name,
	});
	
	return translations;
}

I’m dumping them all into a list of AvailableTranslation objects which I will be unpacking in the UI for displaying the results of the input text translation.

Caching a bit of data!

Now this is something I had kept till the last minute, hence I couldn’t complete it as I expected, but I still managed to store some data in the app memory during run time to reduce repetitive duplicate queries to Bing services, which will also help me reduce the free tier quota usage.

I managed to store the list of destination scenic image result data and translation text in memory as a simple static singleton data object.

Emoji Support 😀

It would be nice to have some Emoji support for our text labels in the app, I thought. So I added it with the following nice little snippet I came across, https://github.com/egbakou/EmojisInXamarinForms

So with that nice little snippet I could insert emojis into a text and bind them to any Label element in Xamarin.Forms, nice and easy!

Title = 
$"Something went wrong 
{new Emoji(0x1F615).ToString()} 
Here is a cat instead!"

It will display the given emoji natively to the run time platform hence we’re using unicode representation of that emoji! 😉

No more icon files!

I really don’t like using physical image files for representing icons, so I got rid of them and introduced full Font Awesome based icons to the entire app. Setting it up in Xamarin.Forms is pretty easy now!

[assembly: ExportFont("fa-regular.otf", Alias = "FontAwesomeRegular")]
[assembly: ExportFont("fa-solid.otf", Alias = "FontAwesomeSolid")]

Like this label that shows a little globe icon using Font Awesome!

<Label
	Margin="0,0,12,0"
	FontFamily="FontAwesomeSolid"
	FontSize="20"
	Text=""
	TextColor="Gray"
	VerticalOptions="Center" />

Yeah Font Awesome is pretty handy!

https://montemagno.com/xamarin-forms-custom-fonts-everywhere/
https://dev.to/codingcoach/using-font-awesome-in-xamarinforms–3mh

Fix Android Status bar…

I know its annoying to deal with Android Status bar styling, and most of the time devs don’t even bother fixing it accordingly to their app theme. They end up leaving the ugly blue color bar at the top of the app.

But I wanted to make it right. May be I am too much of a perfectionist! 😛

<resources>
    <style name="MainTheme.Base"
			parent="Theme.AppCompat.Light.DarkActionBar">
        ...
        <item name="colorPrimary">#bfbfbf</item>
		...
        <item name="colorPrimaryDark">#d9d9d9</item>
        ...
        <item name="colorAccent">#808080</item>
		...
    </style>
</resources>

So I updated the Android Status bar styling values accordingly to my intended color scheme for the app.

PancakeView is yummy!

Yo this right here is a gem, such an awesome element to have in your app, provides loads of features and customization. https://github.com/sthewissen/Xamarin.Forms.PancakeView

It’s super simple to use, where I’ve used it as a container for many elements to provide a beautiful Shadow effect.

<yummy:PancakeView
	Margin="7"
	BackgroundColor="White"
	CornerRadius="20,0,0,40"
	HasShadow="True">
	<Grid Margin="0">
		<Image Aspect="AspectFill" Source="{Binding ImageUrl}" />
	</Grid>
</yummy:PancakeView>

I’ve used this beauty across the entire app in all pages to give a gorgeous gradient effect of Page background as shown below…

<yummy:PancakeView
	BackgroundGradientAngle="40"
	BackgroundGradientEndColor="White"
	BackgroundGradientStartColor="#d9d9d9">
	<Grid>
	...
	</Grid>
</yummy:PancakeView>

I’m so glad I came across this awesome nugget thanks to this challenge! 😀

Beautify XAML…

One thing I noticed in the original project was that the XAML wasn’t properly formatted and it was inconsistent with different tabs and spacing.

I would recommend using any XAML formatting tool in Visual Studio like XAMLStyler which automatically formats your XAML properly while you code. Something nice to have I assume. 😉

Let me make it prettier…

On top of my head, I did not like the UI, not at all. Not blaming the original devs, who’s done a great job putting it together, but I wanted to re-skin it my way, and sprinkle a bit of eye-candy awesomeness… 😉

One thing I love for sure, is building sleek, responsive, minimalistic and yummy looking Mobile App UIs. So that’s what I did. 😀 I decided to implement a minimalistic unified-white color based gradient-ized sleek UI, which called for a whole bunch of restructures in the UI.

So I changed all the color schemes they used and replace them with a white and dark-gray based gradient style in almost all the elements across the app.

Let’s look at those one by one…

Gradient-zing!

Who doesn’t love some good old gradient effects, at least when its well done!

Thanks to the PancakeView we can now easily add this effect to Xamarin.Forms elements, which I have used extensively in my UI design changes as well…

Here’s one example where I modified the AddPicture page with my new color scheme.

Splash it up!

One of the first things I wanted to get rid of was the original splash screen, I did not like it at all, and it was honestly scaring to see a cute little monkey exploding in a high speed animation on the screen. lol

So I change the whole splash screen animation into a smooth zoom-in and fade-out effect as shows in the code below…

private async Task AnimateTransition()
{
	...
	await Task.Delay(1000);

	// Scaling up smoothly upto 5x and Fading out as the next page comes up.
	var explodeImageTask = Task.WhenAll(
		Content.ScaleTo(5, 300, Easing.CubicOut),
		Content.FadeTo(0, 300, Easing.CubicInOut));
	...	
}

Once it completes we navigate to the MainPage. Now that animation was much pleasing to look at…

I felt like that cute little monkey got some justice! lol

Home page!

So like I mentioned before I laid out a full layout design restructure and one of the main pages was the Home page.

  • Getting rid of confusing layout
  • Focusing on the travel photo background
  • Getting rid of the empty space
  • Making sure content properly fills the page

This is a travel related app, so it should be focused on giving such experience for the user so I decided to maximize on the scenic travel photos in the home page, thus resizing the Image element to take up to 70% of the page space.

Also I’ve added navigation for the user to click on the destination name to and to be navigated to that travel destination’s scenic travel photo gallery page.

Look at that beauty eh! 😉

The user picture grid at the bottom, while giving it a fixed height, I managed to fix a whole bunch of alignment issues inside the template container as well.

I added a new element above the translation text element for the user, to select a destination where they would like to view, and navigate to that page from home page itself.

Woot! woot!

Next’s let’s see that beauty in action…

Travel Destination Page…

So from the home page once User selects a travel destination to view, then they get navigated to this gorgeous page filled with scenic travel photos of that destination, pulled from Bing Image Search results…

It gets even better, here’s what you see when you select Italy…

Truly gorgeous… Well I’ve used Pancake View here for the full page background for the gradient effect and shadow effect for the Image containers.

<DataTemplate>
	<yummy:PancakeView
		... >
		<Grid Margin="0">
			<Image Aspect="AspectFill" Source="{Binding ImageUrl}" />
		</Grid>
	</yummy:PancakeView>
</DataTemplate>

Bingo!

Translation revamped!

So as I mentioned before I’ve implemented a new feature extending Bing Translation, allowing the user to pick the languages they want to have their input text translated into.

Here’s the new Page I implemented for it, where I load the list of languages for the user to choose from. I love how Bing translation actually provides the native word for the languages in their own language. 🙂 pretty neat eh!

Once the user selects the languages, I will be saving that in the memory as user preferences. Then next time User enters any text for translation, I would be showing them the list of translations according to their preferred languages. 😀

Now ain’t that handy! 😉

Last minute Pull requested!

Yes, literally last minute! So after all that panic filled sleepless all-nighter effort, I manged to finish up some good looking app with cool features added, and trust me when I say, I literally submitted the Pull Request at the very last minute, exactly at 11:58 PM on April 30, 2020 PDT. Just one minute before the deadline! 😀

Here’s my Pull Request on github: https://github.com/jfversluis/TravelMonkey/pull/25

That was such an adventure, I think this was the first time I stayed up all night for coding, after many years since graduation! 😀

Here’s the repo in my github: https://github.com/UdaraAlwis/TravelMonkey

Well I could have done a much better job, in terms of features, code refactoring and standards, if I hadn’t procrastinated till last minute. I wouldn’t blame someone, if they looked at the code and complained, hence its not the cleanest considering my usual quality standards! but I would consider it was a satisfying completion, given the whole last minute stress and staying up a whole night! 😛

We got Swag!

So as they promised we got them swags yo! 😀

But but… later I got even a better news,

Well at the end all the participants got $25 gift codes to spend at .NET Foundation store! 😀 yaay! 😍

Oh well.. what an adventure! Thank you Microsoft! ❤️

Conclusion

This was such an awesome opportunity, and I’m glad I pulled through somehow even if it was last minute effort! It was actually fun! Learned another lesson not to procrastinate stuff like these till last minute, at least not till 24 hours prior to submission deadline. lol

Sharing a bit of Azure bits, it was surprisingly easy to integrate all these kinds of cool features with Azure Cognitive Services without having to deal with any complicated computing. If it was few years back I would have to deal with all these language translation and image processing stuff all by myself.

So glad I found the new PancakeView thanks to this challenge, it was quite handful, specially in crafting those beautiful gradient and shadow effects.

Finally I should send special thanks to Microsoft and @jfversluis @codemillmatt for this awesome opportunity!

Share the love! 😀 Cheers yol!

Overriding Back Button in Xamarin.Forms Shell…

Let me share all about overriding the Back Button navigation in Xamarin.Forms Shell applications, oh and yes! it includes handling the Android on-screen back button as well! 😉

This topic has been quite a confusing and wobbly area in Xamarin.Forms for the longest time, even I remember having to write numerous customer renderers, and hacks to just to get this simple handle done, overriding the back button…

Yes, we got hope!

But with shiny new Xamarin.Forms Shell seems to have provided quite a promising solution for this, out of the box framework itself, without us having to do much work.

I’ve been working on trying to override the back button behavior on Xamairn.Forms Shell recently, both with Navigation bar button and Android hardware back button. So I decided to share my experience with yol and provide a proper solid solution for your worries.

Ways of the Backwards…

Fundamentally there are two ways how a backward navigation could occur, although there could be other ways depending on the flow of our app…

  • Navigation bar Back button (iOS and Android)
  • Android on-screen Back Button

So when we need to consider both those scenarios when taking control of backward navigation.

Investigation…

Since overriding the Backwards Navigation in Xamarin.Forms has always been quite confusing and difficult to handle, when I started off of Xamarin.Forms Shell, I thought of giving it a clean slate and a fresh try from scratch.

Based on that here are the findings I came up with…

Case 1: OnBackButtonPressed()

OnBackButtonPressed() This method has been there for quite a long time in Xamarin.Forms framework right out of the box, I remember using this long time back, but they kept on breaking its behavior during many releases, which was quite troublesome.

This is suppose to let you override the Android on-screen (hardware) back button action, where a developer can override this method and it would intercept that action giving the developer the option whether to allow it or cancel it.

protected override bool OnBackButtonPressed()
{ ... }

You can override this in a ContentPage but surprisingly, it DOES NOT WORK! Now I would argue it makes total sense for it to be used in such context, and if it worked, it would have made things so much easier, but no, unfortunately not. 😦

But in Xamarin.Forms Shell, if you override this in the AppShell class, it does seem to work. It will intercept every time you click the Android Back button in any page.

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

	protected override bool OnBackButtonPressed()
	{
		// true or false to disable or enable the action
		return base.OnBackButtonPressed();
	}
}

But the only problem is you need to have it implemented in AppShell class, which calls for some complicated implementation in the code,

  • We have to handle each individual Page behavior in a global context
  • No async context available to perform some awaitable async operation

So that’s double the trouble I wouldn’t want to go down that mess! trust me, I’ve tried lol.

They have several bug tickets open for this issue from “time to time”, here’s one of them: https://github.com/xamarin/Xamarin.Forms/issues/7072

Just an extra, if you need to handle an awaitable operation in a non-async context, here’s a sytarting point: https://forums.xamarin.com/discussion/27752/how-to-await-a-displayalert-from-a-page-without-async-button-event

Case 2: Shell.BackButtonBehavior

Shell.BackButton Now this is something new that was shipped with Xamarin.Forms Shell, which lets you override the Navigation Bar Back button, even allowing you to customize the button appearance with an icon or text.

It allows you to cancel the user invoked backward navigation from the Navigation Bar Back button. You could also subscribe a command that will fire up and let you proceed as you wish.

<Shell.BackButtonBehavior>
    <BackButtonBehavior
        Command="{Binding GoBackCommand}"
        IsEnabled="True"
        TextOverride="Back" />
</Shell.BackButtonBehavior>

Microsoft Docs: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/navigation#navigation-events

Do not get this confused with the Android on-screen back button, this does not work for that.

But there’s a small bug in it right now, where as in iOS run time it wouldn’t fire the Command as expected unless you set the TextOverride or IconOverride property. But it works perfectly fine on Android. There’s an active bug on it: https://github.com/xamarin/Xamarin.Forms/issues/8546

Nonetheless this is a good option to keep in mind.

Case 3: Shell.OnNavigating()

Shell.OnNavigating event is also a nifty little feature shipped out with Xamarin.Forms Shell, which allows you to intercept any kind of navigation and override it.

Yes it works on both Android and iOS! allowing you to override any navigation, either forwards or backwards direction. This goes by saying that it supports handling Android on-screen back button navigation as well.

It passes in a parameter, ShellNavigatingEventArgs provides with the following,

  • ShellNavigatingEventArgs.Cancel() allows you to cancel the navigation.
  • ShellNavigatingEventArgs.Source property provides enum ShellNavigationSource, determines the type of navigation.
  • ShellNavigatingEventArgs.Current and ShellNavigatingEventArgs.Target provides the navigation path details, kind of like, from and to path.

Microsoft Docs: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/navigation#navigation-events

There are two ways to implement this, you can override OnNavigating() in the AppShell class

public partial class AppShell : Xamarin.Forms.Shell
{
    public AppShell() { ... }
 
    protected override void OnNavigating
                           (ShellNavigatingEventArgs args)
    {
        // implement your logic
        base.OnNavigating(args);
    }
}

or you can subscribe to the Shell.Current.Navigating event of it as follows…

protected override void OnAppearing()
{
	Shell.Current.Navigating += Current_Navigating;
}

private async void Current_Navigating(object sender, 
                           ShellNavigatingEventArgs e)
{
	// implement your logic
}

Also here you need to make sure to unsubscribe from those even handlers once you’re done with the override action, otherwise they will retain in memory and cause all kinds of weird issues in your app.

Given both solutions, I would say the most productive option is to use the event subscription, instead of overriding in a global context. But then again it should depend mostly on your requirement. You need to keep in mind, “With great power comes great responsibility” when implementing this method, you have to make sure you’re properly handling the resources here.

Case 4: Shell.GoToAsync() for backwards!

Shell.GoToAsync() is the method that is provided by Xamarin.Forms Shell for programmatically navigating forward in pages. Until very recently Shell didn’t provide any way to Navigate backwards, but with one of the latest update they now allow it as follows,

await Shell.Current.GoToAsync("..");

Microsoft Docs: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/navigation#backwards-navigation

This is quite important hence this fills an important part of the puzzle, where we need to override the backward navigation event, but also forward that action programmatically once we confirm it from our logic.

Alternatively you could also use the synchronous method call, which seem to be an Xamarin.Forms internal method,

Shell.Current.SendBackButtonPressed();
...
// or on Page level
page.SendBackButtonPressed();

https://docs.microsoft.com/en-us/dotnet/api/Xamarin.Forms.Page.OnBackButtonPressed?view=xamarin-forms

But I would not recommend this to be used since its synchrony and its meant for Xamarin.Forms internal framework calls.

Investigation Conclusion:

We need both Navigation Bar back button and Android on-screen Back Button to be handled for a complete solution in this case. Now given all 3 cases, we could derive a solution by using Case 2, Case 3, and Case 4 for a full fledge overriding of the Back Button behavior in Xamarin.Forms Shell. So that’s what we’re going to explore next..

Sneak Peek!

Before I get into the actual solution that I built up, let more share a little magic here!

So that’s the awesomeness I’m going to share with you guys! Let me explain…

The Solution…

Just like I explained in my little investigation conclusion, we’re going to make use of both Shell.BackButtonBehavior and Shell.OnNavigating counterparts to implement our overriding of the Back button in Xamarin.Forms Shell. This will take care of both App Navigation Bar back button and Android on-screen back button events.

Navigation bar Back Button: We shall implement the Shell.BackButtonBehavior in the Page with a Command handler attached to it, which will override the Navigation bar back button event, and hold that flow asynchronously until we get a confirmation from an Alert dialog. Once we got the confirmation, we will forward that backward navigation event using GoToAsync(“..”) execution.

Android on-screen Back Button: We could implement the Shell.OnNavigating event subscription to handle the Android back button navigation. This implementation will need a bit of work, hence we’re going to subscribe to the Shell.OnNavigating event upon the Page OnAppearing event and unsubscribe from it upon OnDisappearing event for cleaning up the event handlers. Once we get a hold of the back button event, we will asynchronously await for the Alert dialog confirmation and forward the navigation using GoToAsync(“..”), same as the previous execution.

Keep in mind that I will be showcasing how to handle both these scenarios at once, in perfect synchronous harmony with a beautiful non-conflict implementation. 😉

Additionally I will include them separately as well in my demo project for you to explore them separately as well just in case if you had such requirement. I have published this up in my Github repo, if you’re interested in taking a peak,

hosted on github:
github.com/UdaraAlwis/XFShellBackButtonOverride

Alright then, on ahead…

Before I begin, make sure to update the installed Xamarin.Forms version in your project, whereas for this demo I’m using version 4.6.0.847, so I would recommend using the same or newer version.

Let the coding begin!

Given that you have prepared your Xamarin.Forms Shell project solution, and ready to go, let me recap some basics I’ve set up this project with. I’m using pure out of the box Xamarin.Forms Shell project, with no additional libraries or dependencies. I have set it up accordingly to MVVM architecture with appropriate BindingContext set up for each XAML Page.

Let’s begin with our Navigation bar Back button override implementation, by adding Shell.BackButtonBehavior set up in our XAML Page.

<ContentPage
    ... >
 
    <Shell.BackButtonBehavior>
        <BackButtonBehavior Command="{Binding GoBackCommand}">
            <BackButtonBehavior.TextOverride>
                <OnPlatform x:TypeArguments="x:String">
                    <OnPlatform.Platforms>
                        <On Platform="iOS" Value="Go Back" />
                    </OnPlatform.Platforms>
                </OnPlatform>
            </BackButtonBehavior.TextOverride>
        </BackButtonBehavior>
    </Shell.BackButtonBehavior>
 
    <ContentPage.Content>
        ...
    </ContentPage.Content>
</ContentPage>

Remember the Xamarin.Forms Shell bug I mentioned earlier regarding the iOS run time? So here I’ve come up with a workaround for it by setting TextOverride property for iOS platform. You could even use the IconOverride property as well if it fits your requirement.

Now let’s wire up that Command, GoBackCommand in our ViewModel…

public class TestPageViewModel : BaseViewModel
{
	public Command GoBackCommand { get; set; }

	public TestPageViewModel()
	{
		...
		GoBackCommand = new Command(async () => await GoBack());
	}

	private async Task GoBack()
	{
		var result = await Shell.Current.DisplayAlert(
			"Going Back?",
			"Are you sure you want to go back?",
			"Yes, Please!", "Nope!");

		if (result)
		{
			await Shell.Current.GoToAsync("..", true);
		}
	}
}

As you can see I’ve wired up the Command to the GoBack() async method, where I’ve fired up an Alert dialog for the user awaiting confirmation asynchronously. Then once we get the go ahead confirmation we perform the backward navigation programmatically using GoToAsync(“..”) method.

Now that bit is completed, it should let you handle the Navigation Bar back button event as you wish! 😉

Next let’s take care of the Android on-screen Back button override implementation, by making sure we have hooked into the OnAppearing and OnDisappearing events in our Page, which could differ based on the MVVM library you use. But if you’re using pure Xamarin.Forms here like me, then you can hook up to them as follows…

public partial class TestPage : ContentPage
{
	public TestPage(){ ... } 

	protected override void OnAppearing()
	{
		base.OnAppearing();

		// execute OnAppearingCommand
		// informing ViewModel
		((TestPageViewModel)this.BindingContext)
				.OnAppearingCommand.Execute(null);
	}

	protected override void OnDisappearing()
	{
		base.OnDisappearing();

		// execute OnDisappearingCommand		
		// informing ViewModel
	}
}

The idea here is to inform our ViewModel that the Page is Appearing or Disappearing and based on that we subscribe or unsubscribe from Shell.OnNavigating event as follows…

public class TestPageViewModel : BaseViewModel
{
    ...
    public Command OnAppearingCommand { get; set; }
    ...
  
    public TestPageViewModel()
    {
        ... 
        OnAppearingCommand 
                = new Command(() => OnAppearing());
        ...
    }
 
    private void OnAppearing()
    {
        Shell.Current.Navigating += Current_Navigating;
    }
 
    private void OnDisappearing()
    {
        Shell.Current.Navigating -= Current_Navigating;
    }
 
    private async void Current_Navigating(object sender, 
                                ShellNavigatingEventArgs e)
    {
        if (e.CanCancel)
        {
            e.Cancel();
            await GoBack();
        }
    }
 
    private async Task GoBack()
    {
        // display Alert for confirmation
        ...
 
        if (result)
        {
            Shell.Current.Navigating -= Current_Navigating;
            await Shell.Current.GoToAsync("..", true);
        }
    }
}

As you can see we’re subscribing to Shell.Current.Navigating event based on Appearing and Disappearing events of the page, making sure that we’re cleaning up the event handlers as I explained before.

Here we’re intercepting the Navigation in the Current_Navigating() method, and we immediately cancel it and call up on awaitable GoBack() method, where we do the Alert confirmation for the user. Then from there, based on the confirmation, we perform go back or cancellation, and additionally we’re unsubscribing from the Shell.Current.Navigating event there itself, for preventing circular event.

Here I am unsubscribing from Shell.Current.Navigating in both GoBack() and OnDisappearing() is for safety, but you could handle this according to your own requirement as well.

Afterthought…

You can only keep the 2nd implementation and still have the Navigation Bar back button overridden, this is due to Shell.OnNavigating firing up for any kind of navigation happening in Shell. So you don’t really need to have the Shell.BackButtonBehavior implementation, but you could keep both in case if you need to implement any extra features, or for safe keeping of the navigation state. 😉 Your choice!

Also since the Android on-screen Back Button handling is only required on Android, you could restrict that code logic to be registered only for Android run time using Device.RuntimePlatform == Device.Android flag of Xamarin.Forms framework.

No! I don’t want both!?

Now having both the above implementation will let you override Navigation Bar and Android on-screen back button actions. But what if I only want to override one of them? Good question!

In that case you could only have one of the above implementation up on your choice, but if you want to keep both and dynamically switch between the options, you could easily do that by introducing a simple flag property in your ViewModel such as follows,

public class TestPageViewModel : BaseViewModel
{
    public bool IsBackwardNavAllowed { get; set; } = false;
 
    public TestPageViewModel()
    {
        ...
        NavBarBackButtonCommand = new Command(async () => 
        {
            IsBackwardNavAllowed = true;
            await Shell.Current.GoToAsync("..", true);
        });
        ...
    }
 
    ...
 
    private async void Current_Navigating(object sender, ShellNavigatingEventArgs e)
    {
        if (e.CanCancel && !IsBackwardNavAllowed)
        {
            e.Cancel();
            await GoBack();
        }
    }

    ...
}

Here I have the IsBackwardNavAllowed flag, where I use to allow backward navigation originated from NavBarBackButtonCommand which is bound to Shell.BackButtonBehavior, but I still override the Android on-screen back button navigation event. 😉

Little demo awesomeness!

So in my little demo app, I have implemented 3 separate scenarios of overriding the Back Button Navigation in Xamarin.Forms Shell!

You can take a look at each XAML Page and their ViewModel counter parts to see how I have implemented this awesomeness. Alright then without further a due, let’s see it in action!

Fire it up!

Here in our 1st Page we have Android and iOS side by side both with Navigation Bar Back Button overridden successfully… 😀

You can see here on Android we have the default Back button in the Navigation bar, but on iOS we have the Text overridden back button due workaround I used for fixing the iOS bug I mentioned earlier.

Then in our 2nd Page we have Android on-screen Back button overridden successfully, in which case there wouldn’t be any response to show on iOS obviously…

As you can see I’ve deliberately disabled the overriding of the Navigation Bar Back button action using the implementation that I discussed earlier, hence we’re nicely overriding only the Android on-screen Back Button action.

Finally in our 3rd Page we have Android and iOS side by side with both Navigation Bar Back Button and Android on-screen Back Button overridden successfully…

There you go, Navigation bar back button events are overridden in both Android and iOS, while also overriding the Android on-screen back button event as well! 😉 This this implementation you don’t have to deal with the iOS bug of Shell.BackButtonBehavior…

Oh look at that beauty eh! 😉

hosted on github:
github.com/UdaraAlwis/XFShellBackButtonOverride

Once again feel free to check out the code on github! 😀

Conclusion…

The whole idea of overriding backward navigation in classic Xamarin.Forms was quite tedious, having to implement custom renderers and all kinds of platform specific hacks. But with Xamarin.Forms Shell it seems to be made easier, but still need a bit of work, and few pending bugs needs fixing from Microsofts.

So using the awesomeness of Xamarin.Forms Shell we explored how to override the Navigation Bar Back Button and Android on-screen Back Button events, with multiple customization possibilities for catering to your specific requirements.

Hope this was helpful for any of my fellow devs out there!

Share the love! 😀 Cheers yol!

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 peek.

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 Peek!

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 peek 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!