xamarin forms

Using Microsoft’s Extensions.DependencyInjection package in (Xamarin.Forms) MVVM applications (Part 2)

Using Microsoft’s Extensions.DependencyInjection package in (Xamarin.Forms) MVVM applications (Part 2)

The Key

Our goal is to add keyed registrations to the IServiceCollection, so we need a common denominator to build upon. As I was able to use a string with the SimpleIoc implementation of MVVMLight for years now, I decided to move on with that and created the following, very complex interface:

public interface IViewModelKey
{
    string Key { get; set; }
}

Every ViewModel that should be registered by Key needs to implement that interface from now on in my MVVM environment.

The Resolver

Back in the MVVMLight times, I was able to query the SimpleIoc registrations with the key I was searching for. In the Microsoft.Extensions.DependencyInjection world, things get a bit more complex. While there are different ways to solve the problem (there are some libraries extending the IServiceProvider with additional methods out there, for example), I decided to use the IServiceProvider itself and go down the resolver interface/implementation road.

Let’s have a look at the interface first:

public interface IViewModelByKeyResolver<T> where T : IViewModelKey
{
    public T GetViewModelByKey(string key);
}

Nothing too special here, just a generic implementation of the resolver interface with the requirement of the IViewModelKey implementation from above. This makes the usage pretty straight forward. The more important part here is the implementation, though. Let’s have a look at mine:

public class ViewModelByKeyResolver<T> : IViewModelByKeyResolver<T> where T : IViewModelKey
{
    private readonly IServiceProvider _serviceProvider;

    public ViewModelByKeyResolver(IServiceProvider serviceProvider)
        => _serviceProvider = serviceProvider;

    public T GetViewModelByKey(string key)
        => _serviceProvider.GetServices<T>().SingleOrDefault(vm => vm.Key == key);
}

The registration of the implementation will automatically inject the IServiceProvider instance at runtime for me here. The GetViewModelByKey method searches all registrations of the given type for the key and returns the desired instance.

Registering the Resolver and keyed ViewModels

The registration of the resolver is done like all the other registrations:

this.ServiceDescriptors.TryAddSingleton<IViewModelByKeyResolver<KeyedViewModel>, ViewModelByKeyResolver<KeyedViewModel>>();

Replace KeyedViewModel with your individual type that implements your key interface. That’s it.

For the registration of the KeyedViewModel instances, there is one thing to pay attention to, though. You cannot use the TryAdd{Lifetime} methods here for registration. Instead, just use the Add{Lifetime} method to register them. Here is a sample:

this.ServiceDescriptors.AddSingleton<KeyedViewModel>(new KeyedViewModel("Key1"));
this.ServiceDescriptors.AddSingleton<KeyedViewModel>(new KeyedViewModel("Key2"));
this.ServiceDescriptors.AddSingleton<KeyedViewModel>(new KeyedViewModel("Key3"));
this.ServiceDescriptors.AddSingleton<KeyedViewModel>(new KeyedViewModel("Key4"));
this.ServiceDescriptors.AddSingleton<KeyedViewModel>(new KeyedViewModel("Key5"));

If you know the keyed ViewModels already at the time of your app startup, you can add them right away and create the IServiceProvider instance as shown in my first post. In most cases, however, you will know the information of the keyed instances only at runtime. Luckily, my Xamarin.Forms implementation already has the solution built in. Here is a short reminder:

public ServiceCollection? ServiceDescriptors { get; private set; }

private IServiceProvider? _services;

public IServiceProvider? Services => _services ??= BuildServiceProvider();

public IServiceProvider? BuildServiceProvider(bool resetExisiting = false)
{
    if (this.ServiceDescriptors == null)
        throw new ArgumentNullException($"Please register your Services and ViewModels first with the {nameof(RegisterServices)} and {nameof(RegisterViewModels)} methods.");

    if (resetExisiting)
        _services = null;

    if (_services == null)
        _services = ServiceDescriptors.BuildServiceProvider();

    return _services;
}

The BuildServiceProvider method has an additional parameter that allows to reset the existing IServiceProvider. This way, I can keep my existing registrations and just add the new keyed ones dynamically. Please note that you may need to reinitialize your already registered and used ViewModels under certain circumstances after performing the reset.

Accessing a keyed ViewModel

Last but not least, I need to show you how to access a ViewModel by its key. Luckily, this is not that hard:

KeyedViewModel vm4 = IocManager.Current.Services.GetService<IViewModelByKeyResolver<KeyedViewModel>>().GetViewModelByKey("Key4");
KeyedViewModel vm2 = IocManager.Current.Services.GetService<IViewModelByKeyResolver<KeyedViewModel>>().GetViewModelByKey("Key2");

Conclusion

By switching to the CommunityToolkit.MVVM package and utilizing Microsoft’s Extension.DependencyInjection package together with it, my MVVM environment is ready for upcoming challenges like .NET MAUI. I will be able to use it on all .NET platforms and just need to adapt my Xamarin.Forms implementation to others (which I have done already for one of our internal tools at work in WPF). Even keyed ViewModel instance can be used similarly as before, as I showed you in this post.

As always, I hope this post will be helpful for some of you.

Until the next post, happy coding!

Posted by msicc in Dev Stories, Xamarin, 1 comment
Using Microsoft’s Extensions.DependencyInjection package in (Xamarin.Forms) MVVM applications (Part 1) [Updated]

Using Microsoft’s Extensions.DependencyInjection package in (Xamarin.Forms) MVVM applications (Part 1) [Updated]

As some of you might remember, I was always a big fan of the MVVMLight toolkit. As the later one is now deprecated and MAUI around, I took a look at the CommunityToolkit.Mvvm, which is officially the successor to MVVMLight.

As stated in the documentation of the new Toolkit, one could now use the Microsoft’s Extensions.DependencyInjection package for anything related to Inversion of Control (which used to be handled by the SimpleIoc implementation of MVVMLight before). Because this is also the built-in way for .NET 6 and web applications, I decided to adapt it already now for my Xamarin.Forms apps (especially my new one I am currently working on).

[Update] Nuget packages

Please note that while the toolkit’s source is now separated from the Windows CommunityToolkit, the documentation isn’t. This can be confusing (as it was for me). On top of that, there are now two Toolkit MVVM packages:

I thought I got it right when writing this blog post initially. After Brandon Minnick from Microsoft pointed me to the right package, I realized I was not. Up on further research, I found also this discussion in the GitHub repo, stating the one and only will be the CommunityToolkit package. Please use only this one if you are following my tutorials here. I updated all mentions of the Toolkit in this post accordingly.

Default IServiceProvider implementation

The toolkit has a default implementation for the IServiceProvider provided by the Extension.DependencyInjection package. You can read about it here in the documentation and see the source here on GitHub. It focuses heavily on thread safety, its usage is pretty strict, and it does not allow adding ViewModels dynamically. If you do not need stuff like this in your app, you’re probably fine using the Ioc.Default implementation of the toolkit.

Custom IServiceprovider implementation

In TwistReader, the application I am currently working on, I had my requirements easily resolved by the SimpleIoc implementation of the MVVMLight toolkit. With the Extensions.DependencyInjection package, I had to move on with a custom implementation, on which we will have a deeper look in this post. Before you move on reading, make sure you have read the documentation.

IIocManagerBase interface

Of course, I wanted my custom implementation to be reusable. So I extended my existing base interface that my applications need to implement:

public interface IIocManagerBase 
{
    IServiceProvider? Services { get; }
    ServiceCollection? ServiceDescriptors { get; }

    IServiceProvider? BuildServiceProvider(bool resetExisiting = false);

    void Initialize(bool useDefaultNavigationService = true);

    void RegisterServices(bool useDefaultNavigationService);

    void RegisterViewModels();
}

I added the ServiceDescriptors property as well as an IServiceProvider property including a method to (re)build the ServiceProvider if needed. Let’s continue by having a look at the Xamarin.Forms base implementation.

FormsIocManagerBase base class

Building up on the interface before, I created a base implementation for my Xamarin.Forms apps. Let’s go a bit into the details.

In the Initialize method, I am just calling the RegisterServices and the RegisterViewModels methods. One important thing to notice is that I am instantiating the ServiceDescriptors property in the RegisterViewModels method. I also add my default services already to collection there. The RegisterViewModels method remains empty in the base implementation.

public virtual void Initialize(bool useDefaultNavigationService = true)
{
    RegisterServices(useDefaultNavigationService);
    RegisterViewModels();
}

public virtual void RegisterServices(bool useDefaultNavigationService)
{
    this.ServiceDescriptors = new ServiceCollection();

    this.ServiceDescriptors.TryAddSingleton<IDialogService>(DependencyService.Get<IDialogService>());
    this.ServiceDescriptors.TryAddSingleton<IActionSheetService>(new ActionSheetService());

    if (useDefaultNavigationService)
        this.ServiceDescriptors.TryAddSingleton<INavigationService>(new NavigationService());
    else
        System.Diagnostics.Debug.WriteLine("***** DON'T FORGET TO REGISTER YOUR INavigationService INSTANCE(S)!  *****");
}

public virtual void RegisterViewModels()
{
}

Until I switched to CommunityToolkit.Mvvm, this was all I had in there (using SimpleIoc for service registrations). Now that I am using the Extensions.DependencyInjection package, there is some more work to do:

public ServiceCollection? ServiceDescriptors { get; private set; }

private IServiceProvider? _services;

public IServiceProvider? Services => _services ??= BuildServiceProvider();

public IServiceProvider? BuildServiceProvider(bool resetExisiting = false)
{
    if (this.ServiceDescriptors == null)
        throw new ArgumentNullException($"Please register your Services and ViewModels first with the {nameof(RegisterServices)} and {nameof(RegisterViewModels)} methods.");

    if (resetExisiting)
        _services = null;

    if (_services == null)
        _services = ServiceDescriptors.BuildServiceProvider();

    return _services;
}

The code is not that complex, but helps with the IServiceProvider instance handling. The BuildServiceProvider method has a reset flag that allows me to rebuild the provider at runtime. One scenario where we can use this one is for adding ViewModel registrations dynamically during the runtime of our app, but.

IocManager in-app implementation

The next code block shows a typical in-app implementation of my IocManager. You may have noticed I am using the TryAdd{Lifetime} methods already before when adding items to the ServiceCollection. This makes sure that I have always just one registration and does not throw an exception if I try to add it again. If you prefer the exception, just switch to the Add{Lifetime} version.

public class IocManager : FormsIocManagerBase
{
    private static IocManager _instance;

    public static IocManager Current => _instance ??= new IocManager();


    public override void Initialize(bool useDefaultNavigationService = true)
    {
        base.Initialize(useDefaultNavigationService);
    }

    public override void RegisterServices(bool useDefaultNavigationService)
    {
        base.RegisterServices(useDefaultNavigationService);

        this.ServiceDescriptors.TryAddSingleton<ITestService, TestService1>();
        this.ServiceDescriptors.TryAddScoped<ITestService, TestedTestService>();
    }

    public override void RegisterViewModels()
    {
        this.ServiceDescriptors.TryAddSingleton<MainViewModel>();
        this.ServiceDescriptors.TryAddSingleton<SecondaryViewModel>();
    }

    public MainViewModel MainVm => this.Services.GetRequiredService<MainViewModel>();
    public SecondaryViewModel SecondaryVm => this.Services.GetRequiredService<SecondaryViewModel>();
}

For my Xamarin.Forms applications, I always use the IocManager implementation as a singleton. This makes it pretty easy with the different lifetimes on all platforms. As you can see, there is nothing complicated in the registration process, I just add both my services and my ViewModels to the ServiceCollection.

I also have some convenience properties for the most important ViewModels that make Binding easier (as I tend to keep code behind files as clean as possible). If you need a service in another place in your app, and you are not using constructor injection (which gets automatically resolved by the Microsoft.Extensions.DepedencyInjection package), you can get the instance in the same way as I do with the ViewModel instances above.

Conclusion

Creating a custom IServiceProvider implementation is not that hard. The custom implementation allows one to recreate the IServiceProvider (handle with care!) if needed. In the next post, I will show you how to deal with keyed ViewModel instances when using the Extensions.DependencyInjection package.

Have you already used the Microsoft.Extensions.DependencyInjection package with Xamarin.Forms or other platforms (not web)? What are your experiences? If so, leave a comment or chat with me on Twitter!

As always, I hope this post is helpful for some of you.

Until the next post – happy coding, everyone!

Posted by msicc in Dev Stories, Xamarin, 4 comments
Use the iOS system colors in Xamarin.Forms (Updated)

Use the iOS system colors in Xamarin.Forms (Updated)

Update

After publishing this post, Gerald Versluis from Microsoft responded on Twitter with an interesting information on how to get the system colors into our ResourceDictionary without using the DependencyService:

I had a quick look at the NamedPlatformColor class, but noticed that the implementation in Xamarin.Forms is incomplete. Gerald will try to update them. Once that is done, I will update the library on Github and this post again.

Original version below:


Overview

Let me give you a short overview first. To achieve our goal to use the iOS system colors, we need just a few easy steps:

  1. Xamarin.Forms interface that defines the colors
  2. Xamarin.iOS implementation of that interface
  3. ResourceDictionary to make the colors available in XAML
  4. Merging this dictionary with the application’s resource
  5. Handling of the OnRequestedThemeChanged event

Now that the plan is clear, let’s go into details.

ISystemColors interface

We will use the Xamarin.Forms DependencyService to get the colors from iOS to Xamarin.Forms. Let’s create our common interface:

using Xamarin.Forms;

namespace [YOURNAMESPACEHERE]
{
    public interface ISystemColors
    {
        Color SystemRed { get; }
        Color SystemOrange { get; }
        Color SystemYellow { get; }
        Color SystemGreen { get; }
        Color SystemMint { get; }
        Color SystemTeal { get; }
        Color SystemCyan { get; }
        Color SystemBlue { get; }
        Color SystemIndigo { get; }
        Color SystemPurple { get; }
        Color SystemPink { get; }
        Color SystemBrown { get; }
        Color SystemGray { get; }
        Color SystemGray2 { get; }
        Color SystemGray3 { get; }
        Color SystemGray4 { get; }
        Color SystemGray5 { get; }
        Color SystemGray6 { get; }
        Color SystemLabel { get; }
        Color SecondaryLabel { get; }
        Color TertiaryLabel { get; }
        Color QuaternaryLabel { get; }
        Color Placeholder { get; }
        Color Separator { get; }
        Color OpaqueSeparator { get; }
        Color LinkColor { get; }
        Color FillColor { get; }
        Color SecondaryFillColor { get; }
        Color TertiaryFillColor { get; }
        Color QuaternaryFillColor { get; }
        Color SystemBackgroundColor { get; }
        Color SecondarySystemBackgroundColor { get; }
        Color TertiarySystemBackgroundColor { get; }
        Color SystemGroupedBackgroundColor { get; }
        Color SecondarySystemGroupedBackgroundColor { get; }
        Color TertiarySystemGroupedBackgroundColor { get; }
        Color DarkTextColor { get; }
        Color LightTextColor { get; }
    }
}

As we are not able to change any of the system colors, we are just defining getters in the interface.

The Xamarin.iOS platform implementation

The implementation is straight forward. We are implementing the interface and just get the values for each system color. The list is based on Apple’s documentation for human interface and UI element colors.

using [YOURNAMESPACEHERE];

using UIKit;

using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: Dependency(typeof(SystemColors))]
namespace [YOURNAMESPACEHERE]
{
    //https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/color/
    //https://developer.apple.com/documentation/uikit/uicolor/ui_element_colors

    public class SystemColors : ISystemColors
    {
        #region System Colors
        public Color SystemRed => UIColor.SystemRedColor.ToColor();
        public Color SystemOrange => UIColor.SystemOrangeColor.ToColor();
        public Color SystemYellow => UIColor.SystemYellowColor.ToColor();
        public Color SystemGreen => UIColor.SystemGreenColor.ToColor();
        public Color SystemMint => UIColor.SystemMintColor.ToColor();
        public Color SystemTeal => UIColor.SystemTealColor.ToColor();
        public Color SystemCyan => UIColor.SystemCyanColor.ToColor();
        public Color SystemBlue => UIColor.SystemBlueColor.ToColor();
        public Color SystemIndigo => UIColor.SystemIndigoColor.ToColor();
        public Color SystemPurple => UIColor.SystemPurpleColor.ToColor();
        public Color SystemPink => UIColor.SystemPinkColor.ToColor();
        public Color SystemBrown => UIColor.SystemBrownColor.ToColor();


        public Color SystemGray => UIColor.SystemGrayColor.ToColor();
        public Color SystemGray2 => UIColor.SystemGray2Color.ToColor();
        public Color SystemGray3 => UIColor.SystemGray3Color.ToColor();
        public Color SystemGray4 => UIColor.SystemGray4Color.ToColor();
        public Color SystemGray5 => UIColor.SystemGray5Color.ToColor();
        public Color SystemGray6 => UIColor.SystemGray6Color.ToColor();
        #endregion

        #region UI Element Colors
        public Color SystemLabel => UIColor.LabelColor.ToColor();
        public Color SecondaryLabel => UIColor.SecondaryLabelColor.ToColor();
        public Color TertiaryLabel => UIColor.TertiaryLabelColor.ToColor();
        public Color QuaternaryLabel => UIColor.QuaternaryLabelColor.ToColor();
        public Color Placeholder => UIColor.PlaceholderTextColor.ToColor();
        public Color Separator => UIColor.SeparatorColor.ToColor();
        public Color OpaqueSeparator => UIColor.SeparatorColor.ToColor();
        public Color LinkColor => UIColor.SeparatorColor.ToColor();

        public Color FillColor => UIColor.SystemFillColor.ToColor();
        public Color SecondaryFillColor => UIColor.SecondarySystemFillColor.ToColor();
        public Color TertiaryFillColor => UIColor.TertiarySystemFillColor.ToColor();
        public Color QuaternaryFillColor => UIColor.QuaternarySystemFillColor.ToColor();

        public Color SystemBackgroundColor => UIColor.SystemBackgroundColor.ToColor();
        public Color SecondarySystemBackgroundColor => UIColor.SecondarySystemBackgroundColor.ToColor();
        public Color TertiarySystemBackgroundColor => UIColor.TertiarySystemBackgroundColor.ToColor();

        public Color SystemGroupedBackgroundColor => UIColor.SystemGroupedBackgroundColor.ToColor();
        public Color SecondarySystemGroupedBackgroundColor => UIColor.SecondarySystemGroupedBackgroundColor.ToColor();
        public Color TertiarySystemGroupedBackgroundColor => UIColor.TertiarySystemGroupedBackgroundColor.ToColor();

        public Color DarkTextColor => UIColor.DarkTextColor.ToColor();
        public Color LightTextColor => UIColor.LightTextColor.ToColor();

        #endregion
    }
}

Do not forget to add the Dependency attribute on top of the implementation, otherwise it won’t work.

The ResourceDictionary

As I prefer defining my UI in XAML in Xamarin.Forms, I naturally want those colors to be available there as well. This can be done by loading the colors into a ResourceDictionary. As you might remember, I prefer codeless ResourceDictionary implementations. This time, however, we need the code-behind file to make the ResourceDictionary work for us.

First, add a new ResourceDictionary:

Add_ResourceDictionary_XAML

Then, in the code-behind file, we are using the DependencyService of Xamarin.Forms to add the colors to the ResourceDictionary:

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace [YOURNAMESPACEHERE]
{
    public partial class SystemColorsIosResourceDictionary
    {
        public SystemColorsIosResourceDictionary()
        {
            InitializeComponent();

            this.Add(nameof(ISystemColors.SystemRed), DependencyService.Get<ISystemColors>().SystemRed);
            this.Add(nameof(ISystemColors.SystemOrange), DependencyService.Get<ISystemColors>().SystemOrange);
            this.Add(nameof(ISystemColors.SystemYellow), DependencyService.Get<ISystemColors>().SystemYellow);
            this.Add(nameof(ISystemColors.SystemGreen), DependencyService.Get<ISystemColors>().SystemGreen);
            this.Add(nameof(ISystemColors.SystemMint), DependencyService.Get<ISystemColors>().SystemMint);
            this.Add(nameof(ISystemColors.SystemTeal), DependencyService.Get<ISystemColors>().SystemTeal);
            this.Add(nameof(ISystemColors.SystemCyan), DependencyService.Get<ISystemColors>().SystemCyan);
            this.Add(nameof(ISystemColors.SystemBlue), DependencyService.Get<ISystemColors>().SystemBlue);
            this.Add(nameof(ISystemColors.SystemIndigo), DependencyService.Get<ISystemColors>().SystemIndigo);
            this.Add(nameof(ISystemColors.SystemPurple), DependencyService.Get<ISystemColors>().SystemPurple);
            this.Add(nameof(ISystemColors.SystemPink), DependencyService.Get<ISystemColors>().SystemPink);
            this.Add(nameof(ISystemColors.SystemBrown), DependencyService.Get<ISystemColors>().SystemBrown);


            this.Add(nameof(ISystemColors.SystemGray), DependencyService.Get<ISystemColors>().SystemGray);
            this.Add(nameof(ISystemColors.SystemGray2), DependencyService.Get<ISystemColors>().SystemGray2);
            this.Add(nameof(ISystemColors.SystemGray3), DependencyService.Get<ISystemColors>().SystemGray3);
            this.Add(nameof(ISystemColors.SystemGray4), DependencyService.Get<ISystemColors>().SystemGray4);
            this.Add(nameof(ISystemColors.SystemGray5), DependencyService.Get<ISystemColors>().SystemGray5);
            this.Add(nameof(ISystemColors.SystemGray6), DependencyService.Get<ISystemColors>().SystemGray6);

            this.Add(nameof(ISystemColors.SystemLabel), DependencyService.Get<ISystemColors>().SystemLabel);
            this.Add(nameof(ISystemColors.SecondaryLabel), DependencyService.Get<ISystemColors>().SecondaryLabel);
            this.Add(nameof(ISystemColors.TertiaryLabel), DependencyService.Get<ISystemColors>().TertiaryLabel);
            this.Add(nameof(ISystemColors.QuaternaryLabel), DependencyService.Get<ISystemColors>().QuaternaryLabel);

            this.Add(nameof(ISystemColors.Placeholder), DependencyService.Get<ISystemColors>().Placeholder);
            this.Add(nameof(ISystemColors.Separator), DependencyService.Get<ISystemColors>().Separator);
            this.Add(nameof(ISystemColors.OpaqueSeparator), DependencyService.Get<ISystemColors>().OpaqueSeparator);
            this.Add(nameof(ISystemColors.LinkColor), DependencyService.Get<ISystemColors>().LinkColor);

            this.Add(nameof(ISystemColors.FillColor), DependencyService.Get<ISystemColors>().FillColor);
            this.Add(nameof(ISystemColors.SecondaryFillColor), DependencyService.Get<ISystemColors>().SecondaryFillColor);
            this.Add(nameof(ISystemColors.TertiaryFillColor), DependencyService.Get<ISystemColors>().TertiaryFillColor);
            this.Add(nameof(ISystemColors.QuaternaryFillColor), DependencyService.Get<ISystemColors>().QuaternaryFillColor);

            this.Add(nameof(ISystemColors.SystemBackgroundColor), DependencyService.Get<ISystemColors>().SystemBackgroundColor);
            this.Add(nameof(ISystemColors.SecondarySystemBackgroundColor), DependencyService.Get<ISystemColors>().SecondarySystemBackgroundColor);
            this.Add(nameof(ISystemColors.TertiarySystemBackgroundColor), DependencyService.Get<ISystemColors>().TertiarySystemBackgroundColor);

            this.Add(nameof(ISystemColors.SystemGroupedBackgroundColor), DependencyService.Get<ISystemColors>().SystemGroupedBackgroundColor);
            this.Add(nameof(ISystemColors.SecondarySystemGroupedBackgroundColor), DependencyService.Get<ISystemColors>().SecondarySystemGroupedBackgroundColor);
            this.Add(nameof(ISystemColors.TertiarySystemGroupedBackgroundColor), DependencyService.Get<ISystemColors>().TertiarySystemGroupedBackgroundColor);

            this.Add(nameof(ISystemColors.DarkTextColor), DependencyService.Get<ISystemColors>().DarkTextColor);
            this.Add(nameof(ISystemColors.LightTextColor), DependencyService.Get<ISystemColors>().LightTextColor);

        }
    }
}

That’s all for the implementation. Now let’s start having a look at how to use the whole code we wrote until now.

Merging the ResourceDictionary

In Xamarin.Forms, we are able to merge ResourceDictionary classes to make them available for the whole app or on view/page level only. I consider our above created dictionary as an app-level dictionary. On top, to make it reusable, I put all these classes in a separate multi-platform library, which you can find here on Github.

Please note that the syntax will be a little different if you implement the ResourceDictionary directly in your app. Using the library approach, you will merge the dictionary in this way in App.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<Application
    x:Class="SystemColorsTest.App"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:systemcolors="clr-namespace:MSiccDev.Libs.iOS.SystemColors;assembly=MSiccDev.Libs.iOS.SystemColors">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <systemcolors:SystemColorsIosResourceDictionary />
                <!--  more dictionaries here  -->
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Responding to system theme changes

Even if I personally only change the system theme at runtime for testing themes in my apps, your users may do so frequently. Luckily, it is just a matter of handling an event to handle this scenario. In your App.xaml.cs file, register for the RequestedThemeChanged event within the constructor:

        public App()
        {
            InitializeComponent();

            Application.Current.RequestedThemeChanged += OnRequestedThemeChanged;

            this.MainVm = new MainViewModel();
            MainPage mainPage = new MainPage()
            {
                BindingContext = this.MainVm
            };

            MainPage = mainPage;
        }

As the system colors respond to the system theme change, we need to reload them to get these changes.

Within the OnRequestedThemeChanged method, we are first getting the actual merged ResourceDictionary instance. Then, we will remove this instance and register a new instance of the ResourceDictionary. This will lead to a full reload of the system colors from iOS into the app. Here is the code:

private void OnRequestedThemeChanged(object sender, AppThemeChangedEventArgs e)
{
    ResourceDictionary iosResourceDict = App.Current.Resources.MergedDictionaries.SingleOrDefault(dict => dict.GetType() == typeof(SystemColorsIosResourceDictionary));

    if (iosResourceDict != null)
    {
        App.Current.Resources.MergedDictionaries.Remove(iosResourceDict);
        App.Current.Resources.MergedDictionaries.Add(new SystemColorsIosResourceDictionary());
    }
}

That’s it, we are now ready to use the colors in XAML and our app adapts to system theme changes. Here is a sample XAML which I wrote to test the colors:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="SystemColorsTest.MainPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:SystemColorsTest"
    x:DataType="local:MainViewModel"
    BackgroundColor="{DynamicResource SystemBackgroundColor}">

    <StackLayout>
        <Frame
            Padding="12,42,24,12"
            BackgroundColor="{DynamicResource SystemGray3}"
            CornerRadius="0">
            <Label
                FontSize="36"
                HorizontalTextAlignment="Center"
                Text="iOS SystemColors in XF"
                TextColor="{AppThemeBinding Dark={DynamicResource LightTextColor},
                                            Light={DynamicResource DarkTextColor}}" />
        </Frame>

        <ScrollView>
            <StackLayout BindableLayout.ItemsSource="{Binding SystemColors}">
                <BindableLayout.ItemTemplate>
                    <DataTemplate>
                        <Frame
                            Margin="6,3"
                            x:DataType="local:SystemColorViewModel"
                            BackgroundColor="{Binding Value}">
                            <Label Text="{Binding Name}" />
                        </Frame>
                    </DataTemplate>
                </BindableLayout.ItemTemplate>
            </StackLayout>
        </ScrollView>
    </StackLayout>
</ContentPage>

Please note that I use DynamicResource instead of StaticResource, even if some colors are static. Using DynamicResource forces the app to reload the colors, and there are some that change (like the SystemGray color palette).

Conclusion

Using the iOS system colors in Xamarin.Forms isn’t that complicated with this implementation. If you have more platforms, you could implement the same technique for the other platforms. As I am focusing on iOS for the moment, I just wrote that part. But who knows, maybe this will be extended in the future.

As always, I hope this post will be helpful for some of you.

Until the next post, happy coding, everyone!

Posted by msicc in Dev Stories, iOS, Xamarin, 5 comments
#XFQaD: Compile XAML without code behind in Xamarin.Forms

#XFQaD: Compile XAML without code behind in Xamarin.Forms

How I discovered this #XFQaD

When I was reorganizing the application resources on my current side project, I decided to create some thematically divided ResourceDictionary files. This has led me to do a quick research on Xamarin.Forms resource dictionaries.

If you’re doing this research, you will stumble upon this post from 2018 (!), where the hint to the magic I’ll show you soon was hidden.

Until now, I only used this with ResourceDictionary files. Maybe it will be helpful also for other XAML resources like controls (I will try that in the future).

How to make XAML only files compile

Add a new XAML file (sample is still ResourceDictionary) to your project:

Add_ResourceDictionary

Delete the code behind file, and add your XAML code. Before hitting the Build button, add this line immediately after the .xml file header:

<?xaml-comp compile="true" ?>

This line is where the magic happens. It tells the compiler to include the XAML file in the Build, pretty much like it does with XAML compile attribute in the code behind file.

Conclusion

The only place where I found this hint was the blog post mentioned above. Neither the docs on XAML Compilation nor the docs on resource dictionaries are mentioning this trick. It somehow went quietly from the nightly builds into production code.

Using this trick, we are able to have a more clean project structure. As always, I hope this post will be helpful for some of you.

Until the next post, happy coding!

Posted by msicc in Dev Stories, 9 comments
Dealing with the System UI on iOS in Xamarin.Forms

Dealing with the System UI on iOS in Xamarin.Forms

Having written a few applications with Xamarin.Forms by now, there was always the one part where you have to go platform specific. Over time, this part got easier as the collection of Platform-specifics in the Xamarin.Forms package was growing and growing.

This post will show (my) most used implementations leveraging the comfort of Platform-specifics as well as some other gotchas I collected over time. At the end of this post, you will also find a link to a demo project on my Github.

Large page title

Let’s start on top (literally). With iOS 11, Apple introduced large title’s that go back to small once the user is scrolling the content.

To make your app use this feature, you need two perform two steps. The first step is to tell your NavigationPage instance to prefer large titles. I often do this when creating my apps MainPage in App.xaml.cs:

public App()
{
    InitializeComponent();

    var navigationPage = new Xamarin.Forms.NavigationPage(new MainPage())
    {
        BarBackgroundColor = Color.DarkGreen,
        BarTextColor = Color.White
    };

    navigationPage.On<iOS>().SetPrefersLargeTitles(true);

    MainPage = navigationPage; 
}

This opens the door to show large titles on all pages that are managed by this NavigationPage instance. Sometimes, however, you need to actively tell the page it should use the large title (mostly happened to me in my base page implementation – never was able to nail it down to a specific point. I just opted in to always explicitly handle it on every page. In the sample application for this post, you will find a switch to toggle and untoggle the large title on the app’s MainPage:

On<iOS>().SetLargeTitleDisplay(_useLargeTitle ? 
LargeTitleDisplayMode.Always : 
LargeTitleDisplayMode.Never);

You can read more in the documentation.

StatusBar text color

Chances are high that we are customizing the BarBackgroundColor and BarTextColor properties. Of course, it makes absolutely sense that the StatusBar text follows the BarTextColor. Luckily, there is a Platform-specific for that as well:

if (this.Parent is Xamarin.Forms.NavigationPage navigationPage)
{
    navigationPage.On<iOS>().SetStatusBarTextColorMode(_statusBarTextFollowNavBarTextColor ? 
                             StatusBarTextColorMode.MatchNavigationBarTextLuminosity : 
                             StatusBarTextColorMode.DoNotAdjust);
}

The documentation ends here. However, I always need to add/change the Info.plist file as well:

<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>

Only after adding this value the above-mentioned trick for the StatusBar text works.

On iOS, the NavigationBar has a separator on its bottom. If you want to hide this separator (which always disturbs the view), you can leverage another Platform-specific on your page:

if (this.Parent is Xamarin.Forms.NavigationPage navigationPage)
{
    navigationPage.On<iOS>().SetHideNavigationBarSeparator(_hideNavBarSeparator);
}

Home indicator visibility

All iPhones after the iPhone 8 (except the SE 2) do not have the home button. Instead, they have a home indicator on the bottom of the device (at least in app). If you are trying to set the color on it, I have bad news for you: you can’t (read on to learn why).

You can hide the indicator in your app, however. Just use this Platform-specific:

On<iOS>().SetPrefersHomeIndicatorAutoHidden(_hideHomeIndicator);

Home indicator background color

Hiding the home indicator is a hard measure. Most users do not even really recognize the indicator if it is incorporated into the app’s UI. To better understand how the home indicator works, I absolutely recommend to read Nathan Gitter’s great post on the topic.

The home indicator is adaptive to its surroundings. Most probably using a matching background color is all it needs to integrate the indicator nicely in your app(s).

Safe area

Thanks to the notch and the home indicator, putting content of our apps got trickier than before. However, Xamarin.Forms has you covered as well. All we have to do is to use the SetUseSafeArea Platform-specific – it will allow us to just use the area where we are not covering any System UI like the StatusBar or the home indicator:

On<iOS>().SetUseSafeArea(_useSafeArea);

Conclusion

Even though iOS has some specialties when it comes to the System UI, Xamarin.Forms has the most important tools built in to deal with them. I absolutely recommend creating a base page for your applications and set the most common specifics there. You can find the promised demo project here on Github. Like always, I hope this post is helpful for some of you.

Until the next post, happy coding, everyone!

Posted by msicc in Dev Stories, iOS, Xamarin, 2 comments
Workaround to force Xamarin.Forms WebView to use a dark mode CSS for local content on Android

Workaround to force Xamarin.Forms WebView to use a dark mode CSS for local content on Android

Recently I updated my blog reader app to support the dark mode newer iOS and Android version support. While everything went smooth on iOS and the update is already live in the App Store, I had some more work to do on Android. One of the bigger problems: the WebView I use to view posts does not automatically switch to dark mode with Xamarin.Forms.

What’s causing this problem?

On part of the problem is that the WebView does not support the CSS query “prefers-color-scheme“. This works as intended on iOS however and is a problem specific to Android. You can refer to this issue on the Xamarin.Forms repository on Github.

Workaround

I am not sure if this problem will ever get solved by the Xamarin.Forms team. I tried to play around with some Javascript solutions that are floating around the web to keep just one CSS file. In the end however, I went with a Xamarin.Forms only approach following the KISS principle.

Xamarin.Forms has a working theme detection mechanism. Based on the return value of the Application.Current.RequestedTheme property, I am loading either the dark mode CSS file or the light mode CSS file (which is default in my case).

Shipping the CSS files is easy, we just need to add them to the Assets folder and set the Build action to AndroidAsset. This results in the following structure within the Android project:

All files that are shipped that way are accessible via the android_asset file uri:

<link rel="stylesheet" href="file:///android_asset/dummycss_light.css">

Now that everything is set up in the Android project, let’s head over to the Xamarin.Forms project. In the sample for this post, I am loading a local html file, while I generate the html dynamically in my blog reader app. The idea works the same way in both cases:

private async Task SetThemeAndLoadSource()
{
    _html = await LoadHtmlFromFileAsync();

    _html = Application.Current.RequestedTheme == OSAppTheme.Dark ?
            _html.Replace("light", "dark") :
            _html.Replace("dark", "light");

    this.TestWebView.Source = new HtmlWebViewSource() { Html = _html };
}

As you can see, I just override the light and dark part of the CSS file name I load into the HTML. That’s all the “magic” that needs to happen here. Just one little thing left to add – what if the user changes the theme while the app is running? Xamarin.Forms has the solution built in as well – just handle the RequestedThemeChanged event and override the file name again, followed by setting the HtmlWebViewSource again:

private async void Current_RequestedThemeChanged(object sender, AppThemeChangedEventArgs e)
{
    await SetThemeAndLoadSource();
}

Conclusion

As most of us are already used to, we sometimes need to find some workarounds when dealing with Xamarin.Forms. While this problem could have been solved with a bunch of Javascript and a custom CSS in a WebViewRenderer as well (I tried that, but didn’t like the complexity), you can achieve reliable results with the workaround above just in Xamarin.Forms.

You can find a working sample here on Github. As always, I hope this post will be helpful for some of you.

Until the next post, happy coding, everyone!
Posted by msicc in Android, Dev Stories, Xamarin, 1 comment
Code Snippets for Xamarin.Forms BindableProperty

Code Snippets for Xamarin.Forms BindableProperty

If you haven’t heard about the #XamarinMonth before, you should either click on the hashtag or read Luis’ blog post where he introduces the topic. At the end of his post, you will also find a link to all the contributions.

Why Code Snippets?

Code snippets make it easier to reuse code you write repeatedly during your dev life. For Xamarin Forms, there are no “built-in” snippets, so I decided to start creating my own snippets some time ago. If you want to get started, have a look at the docs.

The Snippets

If you ever wrote a custom control or an Effect for Xamarin Forms, chances are high you also used the BindableProperty functionality. I got tired of remembering the syntax, so I decided to write some snippets for it:

  • BindableProperty (bindp)
  • BindableProperty with PropertyChanged handler (bindppc)
  • Attached BindableProperty (bindpa)
  • Attached BindableProperty with PropertyChanged handler (bindpapc)

You can download all of them from my Github repo.

Once you insert (write shortcut, Tab, Tab) the snippet, you just need to define the name of the property as well as its type and hit enter – that’s it.

Tip: To make sure that the snippets show up with IntelliSense, go to Tools/Options, find the Text Editor section followed by the C# entry. Under IntelliSense, find the option for ‘Snippet behavior‘ and choose ‘Always include snippets‘.

Conclusion

Snippets can save a lot of time. Luckily, the implementation is not that difficult (see docs link above). As always, I hope this post is helpful for some of you.

Until the next post, happy coding, everyone!
Posted by msicc in Dev Stories, Xamarin, 0 comments
#XfEffects: Forms Effect to automatically scale FontSize on Label

#XfEffects: Forms Effect to automatically scale FontSize on Label

Why do I need this?

When working with text, we often have to deal with some or all of the following:

  • dynamic text with different length on every instance
  • multiple devices with different screen resolutions
  • limited number of lines

As the amount of places where I need to automatically scale the FontSize is steadily increasing within my apps, I had to come up with a solution – the AutoFitFontSizeEffect.

The shared code

Of course, every Effect has a shared code part. Like in my first post, there are two classes for this – the Effect wrapper and the static parameter class on top of it. The wrapper is pretty straight forward:

    public class AutoFitFontSizeEffect : RoutingEffect
    {
        #region Protected Constructors

        public AutoFitFontSizeEffect() : base($"XfEffects.{nameof(AutoFitFontSizeEffect)}")
        {
        }

        #endregion Protected Constructors
    }

Like with all effects, we are deriving from RoutingEffect and initializing the class with the effect’s id. As I wanted the effect to be configurable with a minimum and a maximum size, I added a static class that takes these two parameters:

    public static class AutoFitFontSizeEffectParameters
    {
        #region Public Fields

        public static BindableProperty MaxFontSizeProperty = BindableProperty.CreateAttached("MaxFontSize", typeof(NamedSize), typeof(AutoFitFontSizeEffectParameters), NamedSize.Large, BindingMode.Default);
        public static BindableProperty MinFontSizeProperty = BindableProperty.CreateAttached("MinFontSize", typeof(NamedSize), typeof(AutoFitFontSizeEffectParameters), NamedSize.Default, BindingMode.Default);

        #endregion Public Fields

        #region Public Methods

        public static NamedSize GetMaxFontSize(BindableObject bindable)
        {
            return (NamedSize)bindable.GetValue(MaxFontSizeProperty);
        }

        public static NamedSize GetMinFontSize(BindableObject bindable)
        {
            return (NamedSize)bindable.GetValue(MinFontSizeProperty);
        }

        public static double MaxFontSizeNumeric(BindableObject bindable)
        {
            return Device.GetNamedSize(GetMaxFontSize(bindable), typeof(Label));
        }

        public static double MinFontSizeNumeric(BindableObject bindable)
        {
            return Device.GetNamedSize(GetMinFontSize(bindable), typeof(Label));
        }

        public static void SetMaxFontSize(BindableObject bindable, NamedSize value)
        {
            bindable.SetValue(MaxFontSizeProperty, value);
        }

        public static void SetMinFontSize(BindableObject bindable, NamedSize value)
        {
            bindable.SetValue(MinFontSizeProperty, value);
        }

        #endregion Public Methods
    }

Let’s break that class down. First, I created two attached BindableProperty objects of type NamedSize. The NamedSize enumeration makes it easy for us to determine the minimum and maximum sizes. If you want to know the values behind the enum entries, check this table in the docs.

To get and set those values out of the BindableProperty, I implemented corresponding methods. As we will see later on, I implemented also two methods that get the numeric values, which will be used in our platform-specific implementations.

Android implementation

Android has a built-in method on TextView to achieve the auto-scaling functionality we desire (read more about it on the Android docs). This makes the implementation pretty straight forward:

    public class AutoFitFontSizeEffect : PlatformEffect
    {
        #region Protected Methods

        protected override void OnAttached()
        {
            if (this.Control is TextView textView)
            {
                if (AutoFitFontSizeEffectParameters.GetMinFontSize(this.Element) == NamedSize.Default &&
                    AutoFitFontSizeEffectParameters.GetMaxFontSize(this.Element) == NamedSize.Default)
                    return;

                var min = (int)AutoFitFontSizeEffectParameters.MinFontSizeNumeric(this.Element);
                var max = (int)AutoFitFontSizeEffectParameters.MaxFontSizeNumeric(this.Element);

                if (max <= min)
                    return;

                textView.SetAutoSizeTextTypeUniformWithConfiguration(min, max, 1, (int)ComplexUnitType.Sp);
            }
        }

        protected override void OnDetached()
        {
        }

        #endregion Protected Methods
    }

Before using the SetAutoSizeTextTypeUniformWithConfiguration method on the TextView, I am running two checks: one if both parameters are set to NamedSize.Default, and the other one if the minimum value is bigger than the maximum value. If we pass past these check, we are using the above mentioned method. That is already everything it needs to make the text scaling automatically within the bounds of the TextView on Android.

iOS implementation

Like Android, also iOS has a pretty easy way to automatically scale the FontSize:

    public class AutoFitFontSizeEffect : PlatformEffect
    {
        #region Protected Methods

        protected override void OnAttached()
        {
            if (this.Control is UILabel label)
            {
                if (AutoFitFontSizeEffectParameters.GetMinFontSize(this.Element) == NamedSize.Default &&
                    AutoFitFontSizeEffectParameters.GetMaxFontSize(this.Element) == NamedSize.Default)
                    return;

                var min = (int)AutoFitFontSizeEffectParameters.MinFontSizeNumeric(this.Element);
                var max = (int)AutoFitFontSizeEffectParameters.MaxFontSizeNumeric(this.Element);

                if (max <= min)
                    return;

                label.AdjustsFontSizeToFitWidth = true;
                label.MinimumFontSize = (float)min;
                label.Font = label.Font.WithSize((float)max);
            }
        }

        protected override void OnDetached()
        {
        }

        #endregion Protected Methods
    }

We are running the same checks as on Android before we are effectively changing the properties on the UILabel that will make the text scale automatically. With setting AdjustsFontSizeToFitWidth to true and setting the MinimumFontSize to our min value as well as the max value as FontSize, we have already done everything it needs on iOS.

Conclusion

The checks we run before using the codes are not random. It may happen that you only add the effect to your Xamarin.Forms.Label without setting the MinFontSize and MaxFontSize. In this case, I am just returning.

Besides mixing up the sizes, the main reason for the second check is that the platform-specific size values are different between platforms. Also in this case, I am just returning.

Besides that, we are able to use all other properties of the default Xamarin.Forms.Label implementation, with MaxLines and LineBreakMode being the two most important ones.

As always, I hope this post will be helpful for some of you. Of course, the sample project for this series is updated on GitHub.

Happy coding, everyone!

Posted by msicc in Android, Dev Stories, iOS, Xamarin, 3 comments
My 2019 (a short review)

My 2019 (a short review)

Bitcoin, Crypto payments & Linux (moving out of my comfort zone)

At the beginning of 2019, I was working on the C#-SDK for AtomicPay, a crypto payment provider. I was also working on a mobile administration app for AtomicPay but during the year, the regulatory rules changed in Switzerland for KYC (know your customer). I had to stop my efforts in this area because, for an indie developer, they are just impossible to handle.

That didn’t stop me to discover other crypto/blockchain stuff, and so I did move out of my comfort zone to play around with a Linux Server and implementing a Bitcoin full node on it. You can read more on this in the Crypto&Blockchain section of my blog.

Even though my efforts have shifted back towards mobile applications, the blockchain area is still of interest to me.

Xamarin, Xamarin, Xamarin

All of my mobile side projects this year were deeply tied into the Xamarin universe. The biggest milestone I finally achieved this year was to finish the porting of my very first application ever from Windows Phone to Android and iOS. I wrote about some of the things I learned right here:

Barcode Scanning

The last few weeks I was busy to write a barcode scanning control for Xamarin Forms that uses native capabilities on iOS and Firebase ML on Android. It was only last week that I finally got both variants working.

Blogging

I attempted to write more regularly this year, but I clearly failed to keep up with it. One of my new year’s resolution is to keep a steady schedule of writing, as the list of what I want(ed) to write about is growing. I will go through this list during my upcoming vacation and try to find a better rhythm for my blogging efforts besides work and working on my side projects.

This year’s review is a bit different from the years before. I kept it short, focusing on the important parts (from my point of view). There is just one thing left to do in this post – to wish you all

A Merry Xmas and a Happy New Year!

Title-Image by Johan L from Pixabay

Posted by msicc in Dev Stories, Editorials, 0 comments
What I’ve learned from porting my first app ever to Android and iOS with Xamarin

What I’ve learned from porting my first app ever to Android and iOS with Xamarin

What’s the app about?

The app is about fishing knots. It sounds boring for most people, but for me, this app made me becoming a developer. So I have a somewhat emotional connection to it. It was back in time when Windows Phone 7 was new and hot. A new shiny OS from Microsoft, but clearly lacking the loads of apps that were available on iOS and Android. At that time, I also managed to get my fishing license in Germany.

As I had a hard time to remember how to tie fishing knots, I searched the store and found… nothing. I got very angry over that fact, partly because it meant I had to use one of the static websites back then, but more about the fact that there was this damn app gap (WP7 users will remember). So I finally decided to learn how to write code for Windows Phone and wrote my first app ever after some heavy self-studying months.

Why porting it?

Writing code should soon become my favorite spare-time activity, effectively replacing fishing. And so the years went on, I made some more apps (most of them for Windows Phone) and also managed to become employed as a developer. After some time, S. Nadella became the CEO of Microsoft, and Windows for mobile phones was dead. So I had created all my “babies”, and they were now set to die as Windows Phone/Mobile did. Not accepting this, I started to create a plan to port my apps over to the remaining mobile platforms. After Facebook effectively killed my most successful app (UniShare – that’s another story, though), I stopped porting that one and started with Fishing Knots +.

Reading your own old code (may) hurt

When I was starting to analyze which parts of the code I could reuse, I was kind of shocked. Of course, I knew that there was this code that I wrote when I didn’t know it better, but I refused to have a look into it and refactor it (for obvious reasons from today’s perspective). I violated a lot of best practices back then, the most prominent ones

  • No MVVM
  • Repeating myself over and over again
  • Monster methods with more than 100 lines within

In the end, I did the only right thing and did not reuse any line of my old code.

Reusing the concept without reusing old code

After I took the right decision to not use my old codebase, I needed to abstract the concept from the old app and translate it into what I know now about best practices and MVVM. I did not immediately start with the implementation, however.

The first thing I did was drawing the concept on a piece of paper. I used a no-code language in that sketch and asked my family if they understand the idea behind the app (you could also ask your non-tech friends). This approach helped me to identify the top 3 features of the app:

  • Controllable animation of each knot
  • Easy-to-follow 3-step instructions for each knot
  • Read-Aloud function of the instructions

Having defined the so-called “Minimum Viable Product“, I was ready to think about the implementation(s).

The new implementation

Finding the right implementation isn’t always straight forward. The first thing I wrote was the custom control that powers the controllable animation behind the scenes. I wrote it out of the context in a separated solution as I packed it into a NuGet package after finishing. It turned out to be also the most complex part of the whole app. It uses a common API in Xamarin.Forms, and custom renderers for Android and iOS. I had to go that route because of performance reasons – which is one of the learnings I took away from the porting.

It was also clear that I will use the MVVM pattern in the new version. So I was setting up some basic things using my own Nuget packages that I wrote during working on other Xamarin based projects.

When it came to the overall structure of my app, I thought a Master/Detail implementation would be fine. However, somehow this never felt right, and so I turned to Shell (which was pretty new, so I tried to give it a shot). In the end, I went with a more custom approach. The app uses a TabbedPage with 3 tabs, one being for the animation, the second for the 3-Step tutorial, and last but not least the Settings/About page. The first two pages share a custom top-down menu implementation, bound to the same ViewModel for its items and selection.

More Xamarin.Forms features I learned (to love)

Xamarin and Xamarin.Forms itself are already powerful and have matured a lot since the time I used it to write my first Xamarin app for Telefonicá Germany. Here is a (high level) list of features I started to use:

  • Xamarin.Essentials – the one library that kickstarts your application – seriously!
  • Xamarin Forms Animations – polish the appearance of your app with some nice looking visual activity within the UI
  • Xamarin Forms Effects – easily modify/enhance existing controls without creating a full-blown custom renderer
  • Xamarin Forms VisualStateManager – makes it (sometimes) a whole lot easier to change the UI based on property changes
  • Xamarin.Forms Triggers – alternative approach to modify the UI based on property changes (but not limited to that)

The three musketeers

Because of Xamarin and Xamarin.Forms are such powerful tools, you may run into the situation of needing help/more information. My three musketeers to get missing information, implementation help or solution ideas:

  • Microsoft Xamarin Docs – the docs for Xamarin are pretty extensive and by reading them (even again), I often had one of these “gotcha!”- moments
  • Github – if the docs don’t help, Github may. Be it in the issues of Xamarin(.Forms) or studying the renderers, Github has been as helpful as the docs to me.
  • Web Search – chances are high that someone had similar problems/ideas solved and wrote a blog about it. I don’t blindly copy those solutions. First I read them, then I try to understand them and finally, I implement my own abstraction of them. This way, I am in a steady learning process.

Learn to understand native implementations

I guarantee you will run into a situation where the musketeers do not help when focusing solely on Xamarin. Accept the situation that Xamarin is sitting on top of the native code of others and does the heavy conversion for us. Learn to read Objective-C, Swift, Java and Kotlin code and translate it into C# code. Once you found possible solutions in one of the native samples, blog posts or docs, you will see that most of them are easy to translate into Xamarin code. Do not avoid this part of Xamarin development, it will help you in future, trust me.

Conclusion

Porting over my first app ever to Android and iOS has provided me not only a lot of fun but also huge learnings/practicing. Some of them are of behavioral nature, some of them are code implementations. This post is about the behavioral part – I will write about some of the implementations in my upcoming blog posts.

I hope you enjoyed reading this post. If you have questions or have similar experiences and want to discuss, feel free to leave a comment on this post or connect to me via social media.

Until the next post, happy coding!

Helpful links:

Posted by msicc in Dev Stories, Xamarin, 2 comments