We’ve come to the final post in this series on Mobile Blazor Bindings (MBB). In part 3, we learned about different ways to manage the state of our MBB applications. From simple state held in components to a central state container. We then looked at data, and how we could persist data locally using the SQLite database, as well as back to an API using HttpClient
. Finally, we applied what we’d learned to our Budget Tracker app.
In this post, we’re going to talk about navigation in MBB. We’re also going to take a look at Xamarin Essentials, a collection of cross platform operating system and platform APIs we can use from C# to do some cool stuff in our MBB applications.
Navigation
Coming from the web, we’re used to being able to navigate between pages in our apps using URLs. For example, www.mysite.com/about would take us to the about page. And generally speaking, users are free to navigate between pages in any order they choose.
Mobile apps tend to use a stack based navigation system where every time the user navigates to a new page it’s added to the top of a stack. They can then move around the app in a linear fashion by tapping on new pages to go forwards and using the devices back button or a swipe gesture to move backwards.
There are different page types, such as MasterDetailPage and TabbedPage, which give the feeling of a more free movement. But essentially you are just moving around within a defined set of sub pages.
At the time of writing, there is no formal way to navigate between pages in MBB – This infrastructure isn’t in place yet. However, there is a sample application in the MBB repo called Xaminals. This does demonstrate a way of navigating using multiple pages using something called Shell navigation.
Shell navigation is a URI-based navigation system for Xamarin applications. This is great for us developers coming from a web background as it naturally fits with the paradigms we’re used to working with. It also uses concepts like routes which fit well with Blazors web based hosting models.
However, I did some experimenting with this technique but I just couldn’t get things to do what I wanted. The biggest hurdle which I couldn’t overcome was setting a starting page for the application. Also as Shell navigation isn’t an official way to navigate, you can’t get parameters populated from the “route” as you would in web based Blazor apps. However, you could overcome this by pulling any required state from a central state container like we talked about in part 3.
I think for me, navigation is just a little to alpha right now so I’m going to wait and see what comes down the line. Luckily, our Budget Tracker app doesn’t need multiple pages so it won’t impact us in any way.
Xamarin Essentials
So far, we’ve talked a lot about the fundamentals required to start building native mobile apps with MBB. But what about doing some more advanced/cool things like Geolocation or making the device vibrate. That’s where Xamarin Essentials comes in.
Xamarin Essentials offers a set of operating system and platform APIs which we can use from C#. Those of you who’ve been following this series will know that we’ve briefly mentioned Xamarin Essentials in part 3 where we talked about using the Connectivity feature to decide whether to save data locally or to an API. But that was just the tip of the iceberg, here’s the full list of features available from Xamarin Essentials right now.
- Accelerometer – Retrieve acceleration data of the device in three dimensional space.
- App Information – Find out information about the application.
- App Theme – Detect the current theme requested for the application.
- Barometer – Monitor the barometer for pressure changes.
- Battery – Easily detect battery level, source, and state.
- Clipboard – Quickly and easily set or read text on the clipboard.
- Color Converters – Helper methods for System.Drawing.Color.
- Compass – Monitor compass for changes.
- Connectivity – Check connectivity state and detect changes.
- Detect Shake – Detect a shake movement of the device.
- Device Display Information – Get the device’s screen metrics and orientation.
- Device Information – Find out about the device with ease.
- Email – Easily send email messages.
- File System Helpers – Easily save files to app data.
- Flashlight – A simple way to turn the flashlight on/off.
- Geocoding – Geocode and reverse geocode addresses and coordinates.
- Geolocation – Retrieve the device’s GPS location.
- Gyroscope – Track rotation around the device’s three primary axes.
- Launcher – Enables an application to open a URI by the system.
- Magnetometer – Detect device’s orientation relative to Earth’s magnetic field.
- MainThread – Run code on the application’s main thread.
- Maps – Open the maps application to a specific location.
- Open Browser – Quickly and easily open a browser to a specific website.
- Orientation Sensor – Retrieve the orientation of the device in three dimensional space.
- Permissions – Check and request permissions from users.
- Phone Dialer – Open the phone dialer.
- Platform Extensions – Helper methods for converting Rect, Size, and Point.
- Preferences – Quickly and easily add persistent preferences.
- Secure Storage – Securely store data.
- Share – Send text and website uris to other apps.
- SMS – Create an SMS message for sending.
- Text-to-Speech – Vocalize text on the device.
- Unit Converters – Helper methods to convert units.
- Version Tracking – Track the applications version and build numbers.
- Vibrate – Make the device vibrate.
- Web Authenticator - Start web authentication flows and listen for a callback.
I think you’ll agree there is a lot of cool stuff there to explore. I’m not going to talk about each item here, I’ll leave it to you to explore the particular features you’re interested in. I’ve included a link with each feature to it’s docs page to get you started.
Adding Dark Mode to Budget Tracker
To finished things off we’re going to use one of the features from Xamarin Essentials to add a dark mode options to Budget Tracker. I mean, let’s face it, it’s not a real app unless it has a dark mode! 😆
We’re going to use the App Theme feature which will allow us to ask for the current theme set on the OS. This will return one of three options to us, Dark
, Light
or Unspecified
. Based on this, we can load a different style sheet for either light or dark mode. It’s worth pointing out that this feature only works on the newer versions of Android and iOS, here are the specifics:
- Android 10+ (API level 29+) - Older versions return
Light
- iOS 13+ - Older versions return
Unspecified
Creating a Dark Theme
To start we’ll rename the existing stylesheet to BudgetTrackerLight.css
and then make a copy of it and call that BudgetTrackerDark.css
. In here we’ll update the various styles with the new dark colour scheme.
entry {
font-size: 30;
color: #F7FAFC;
background-color: #718096;
}
frame {
border-radius: 10;
background-color: #4A5568;
}
label {
color: #CBD5E0;
-xf-horizontal-text-alignment: center;
}
button {
background-color: #718096;
color: #E2E8F0;
}
.textSmall {
font-size: 12;
}
.homeContainer {
padding: 10;
background-color: #1A202C;
}
.balanceContainer {
margin: 0 0 10 0;
-xf-spacing: 0;
}
.balanceContainer > .currentBalance {
font-size: 30;
color: #F7FAFC;
-xf-vertical-text-alignment: center;
-xf-horizontal-text-alignment: center;
}
.budgetContainer {
-xf-spacing: 0;
}
.budgetContainer > .currentBudget {
font-size: 20;
color: #48BB78;
-xf-vertical-text-alignment: center;
-xf-horizontal-text-alignment: center;
}
.expensesContainer {
-xf-spacing: 0;
}
.expensesContainer > .currentExpenses {
font-size: 20;
color: #E53E3E;
-xf-vertical-text-alignment: center;
-xf-horizontal-text-alignment: center;
}
.currencySymbol {
color: #718096;
font-size: 30;
-xf-vertical-text-alignment: center;
}
.createExpenseContainer {
margin: 20 0 0 0;
-xf-orientation: horizontal;
}
.createExpenseContainer > entry {
font-size: initial;
background-color: #718096;
color: #F7FAFC;
-xf-placeholder-color: #CBD5E0;
}
.expenseListItem {
margin: 10 0 0 0;
-xf-orientation: horizontal;
}
.expenseListItem > label {
font-size: 20;
color: #F7FAFC;
}
.noExpenses {
font-size: 16;
color: #A0AEC0;
padding: 10;
-xf-horizontal-text-alignment: center;
}
Now we have the styles sorted out we just need to add a bit of logic to the HomePage
component to load the right stylesheet based on the device’s theme.
Loading the correct stylesheet
We’re going to add a new field to the HomePage
component which will store the theme. Then in the OnInitializedAsync
method we’re going to set the field using the AppInfo.RequestedTheme
which is provided by Xamarin Essentials.
private AppTheme theme;
protected override async Task OnInitializedAsync()
{
theme = AppInfo.RequestedTheme;
// ... other code omitted
}
Now we have that in place it’s just a case of using it to load the correct stylesheet. At the top of the component where we declare the stylesheet we’re going to replace it with the following code.
@if (theme == AppTheme.Light)
{
<StyleSheet Resource="BudgetTrackerLight.css" Assembly="GetType().Assembly" />
}
else if (theme == AppTheme.Dark)
{
<StyleSheet Resource="BudgetTrackerDark.css" Assembly="GetType().Assembly" />
}
else
{
<StyleSheet Resource="BudgetTrackerLight.css" Assembly="GetType().Assembly" />
}
I appreciate this isn’t the most sophisticated code in the world, but for our simple app it will work nicely. We can now run the app and see how things have turned out.
We now have a nice dark mode for our Budget Tracker app which will adjust based on the users preference set on the device. And it was all pretty painless to setup thanks to the features provided by Xamarin Essentials!
You can find the full source code on GitHub.
Summary
In this post, we’ve talked about navigation in Mobile Blazor Bindings, covering the current limitations in the framework. We then talked about Xamarin Essentials and what that offers us. We finished up by applying the App Theme feature from Xamarin Essentials to the Budget Tracker app so that we could show a dark mode if the user had that set as their display preference.
I hope you’ve enjoyed this series on Mobile Blazor Bindings and I’ve piqued your interest in the technology. As I’ve said many times through this series, this is an experiment and there is no official commitment to deliver this. So please only use it for fun right now. But if you’re interested in seeing this become a real product, let the team know either via GitHub or on Twitter.