iOS

Xamarin Forms, the MVVMLight Toolkit and I: loading bundled assets in the Forms project

Xamarin Forms, the MVVMLight Toolkit and I: loading bundled assets in the Forms project

The scenario …

The reason I came up with this is that I am writing on an Xamarin.Forms web reader app. It is an app that uses a  WebView to display the contents of web articles. Of course, I am using a CSS-file to style the content that gets displayed. I am using the default font of every platform, plus some platform specific settings in there. The easiest way to get it working right is to give every platform its own CSS-file. In the Xamarin.Forms project however, I just want to call one method that gets the thing done.

For this scenario, the well documented Files access in Xamarin.Forms does not work.

This post will not yet be reflected in my ongoing XfMvvmLight project on Github as I have another one building on top of this in my queue. Once the second one is written, the project will show these changes, too. This post will contain the full classes however, so you could C&P them if you want/need.

DependencyService and another interface

If you are following this series already, you might already know that the easiest way to achieve my goal is to use the built-in Xamarin.FormsDependencyService and the needed interface with the native implementations.

So let’s start with the interface:

namespace XfMvvmLight.Abstractions
{
    public interface IAssetPathHelper
    {
        string GetResourceFolderPath(string folderName, bool forWeb = false);

        string GetResourcePath(bool forWeb = false);

        string GetResourceFilePath(string folder, string fileName, bool forWeb = false);
    }
}

The interface dictates three string-returning methods that will either return the base path of the platform resources, a specific folder or the full path to the bundled file. This interface covers most usage scenarios I came across. Feel free to leave any feedback if I am missing out a common one.

The only thing left to do is to register the interface in our ViewModelLocator, like we did already before in the RegisterServices() method:

var assetPathHelper = DependencyService.Get();
SimpleIoc.Default.Register(()=> assetPathHelper);

We are getting the platform implementation via the built in DependecyService and assign in to our Xamarin.Forms interface (like we have done already before). By registering it with our SimpleIoc instance, we can now use it wherever we want in our Xamarin.Forms project.

Platform implementations

Android

If you add files in the Resources folder, you can easily access them via the Resource class in your Android project. However, files like CSS-files are normally placed within the Assets folder of your Xamarin.Android project.

Depending on the usage scenario, we have two ways to access the files in the ‘Assets’ folder. If we are residing in the Xamarin.Android project and want to access the content of those bundled assets, we are able to access them using the Android.App.Context.Assets property and assign it to the Android.Content.Res.AssetManager class. We can then use streams to get the data contained in those files.

This does not help however if we want to access those files from a WebView (both in the Android and the Xamarin.Forms project), that’s why we have to use the ‘file:///android_asset‘ uri-scheme. Here is the platform implementation:

using XfMvvmLight.Abstractions;
using XfMvvmLight.Droid.PlatformImplementation;
using System.Diagnostics;
using System.IO;

[assembly: Xamarin.Forms.Dependency(typeof(AssetPathHelper))]
namespace XfMvvmLight.Droid.PlatformImplementation;
{
    public class AssetPathHelper : IAssetPathHelper
    {
        public string GetResourceFolderPath(string folderName, bool forWeb = false)
        {
            return Path.Combine(GetResourcePath(),folderName);
        }

        public string GetResourcePath(bool forWeb = false)
        {
            //reminding ourselves to double check if this way is really necessary
            if (!forWeb)
            {
                Debug.WriteLine("**********************************");
                Debug.WriteLine("You should consider using AssetManager if you are not using this in a WebView.");
                Debug.WriteLine("See: https://developer.xamarin.com/guides/android/application_fundamentals/resources_in_android/part_6_-_using_android_assets/");
                Debug.WriteLine("**********************************");
            }
            
            //but we are always returning the uri scheme 
            return $"file:///android_asset"; 
        }

        public string GetResourceFilePath(string folder, string fileName, bool forWeb = false)
        {
            var folderPath = string.IsNullOrEmpty(folder) ? GetResourcePath() : GetResourceFolderPath(folder);

            return Path.Combine(folderPath,fileName);
        }
    }
}

The implementation is pretty straight forward. Although we could call all three methods, the one we use probably the most is the GetResourceFilePath method. It will give us the complete path to the resource file, which we can then use in our calling code of our Xamarin.Forms project.

By using the Path.Combine method we make sure we get a valid file path string, which is exactly what we need if we are accessing assets in this way. As most of the scenarios for accessing assets could be easily covered by using AssetManager (see above), I am printing a reminder message that it exists to the output window of VisualStudio.

Important: you have to make sure the Build Action of your files is set to AndroidAsset, otherwise you’ll see nothing, in some scenarios it will even throw exceptions. This accounts for the AssetManager as well as for the AssetPathHelper implementations.

iOS

On iOS, we are able to access bundled assets via the NSBundle class. The implementation is even easier than the one for Android, as this is the only way to get those assets. That’s why we are ignoring the forWeb parameter in this case. Here is the implementation:

using System.IO;
using Foundation;
using XfMvvmLight.Abstractions;
using XfMvvmLight.iOS.PlatformImplementation;

[assembly: Xamarin.Forms.Dependency(typeof(AssetPathHelper))]
namespace XfMvvmLight.iOS.PlatformImplementation
{
    //forWeb is ignored on iOS!
    public class AssetPathHelper : IAssetPathHelper
    {
        public string GetResourceFolderPath(string folderName, bool forWeb = false)
        {
            return Path.Combine(GetResourcePath(), folderName);
        }

        public string GetResourcePath(bool forWeb = false)
        {
            return NSBundle.MainBundle.BundlePath;
        }

        public string GetResourceFilePath(string folder, string fileName, bool forWeb = false)
        {
            var folderPath = string.IsNullOrEmpty(folder) ? GetResourcePath() : GetResourceFolderPath(folder);

            return Path.Combine(folderPath, fileName);
        }
    }
}

Important: Make sure your files have the Build Action set to BundleResource, because otherwise you will once again get some errors flying around your head.

UWP

The implementation of the UWP Assets is once again the one with the most places involved. Let’s have a look at the implementation itself first:

using System.IO;
using XfMvvmLight.Abstractions;

namespace XfMvvmLight.UWP.PlatformImplementations
{
    public class AssetPathHelper : IAssetPathHelper
    {
        public string GetResourceFolderPath(string folderName, bool forWeb = false)
        {
            return Path.Combine(GetResourcePath(forWeb),folderName);
        }

        public string GetResourcePath(bool forWeb = false)
        {
            if (forWeb)
            {
                return $"ms-appx-web:///";
            }
            else
            {
                return $"ms-appx:///";
            }
        }

        public string GetResourceFilePath(string folder, string fileName, bool forWeb = false)
        {
            var folderPath = string.IsNullOrEmpty(folder) ? GetResourcePath(forWeb) : GetResourceFolderPath(folder, forWeb);

            return Path.Combine(folderPath,fileName);
        }
    }
}

The UWP platform uses a separate uri-scheme for all web related things. That’s where the  forWeb parameter comes in handy. If we are not loading a bundled asset for the web, we can use this implementation for other resources as well (bundled placeholder images are a good example here).

The next step is to add the assembly again to the list of assemblies that must be included, like we have done before in the OnLaunched method within App.xaml.cs:

//modified for .NET Compile
//see https://developer.xamarin.com/guides/xamarin-forms/platform-features/windows/installation/universal/#Target_Invocation_Exception_when_using_Compile_with_.NET_Native_tool_chain
List<Assembly> assembliesToInclude =
    new List<Assembly>
    {
        typeof(OsVersionService).GetTypeInfo().Assembly,
        typeof(PlatformDialogService).GetTypeInfo().Assembly, 
        typeof(AssetPathHelper).GetTypeInfo().Assembly
    };

The last step involved in the UWP project is to register the implementation with the DependencyService
after the Xamarin.Forms framework is initialized:

Xamarin.Forms.DependencyService.Register<AssetPathHelper>();

The resources should be packed with a Build Action of Content for the UWP platform.

Back to the Xamarin.Forms project

Now that we have everything in place on our platform projects as well as our Xamarin.Forms project, we finally can start using these methods. Here is an example of loading a CSS-file into a string. We can pass this string together with an HTML-string into a HtmlWebViewSource:

private static string GetCssString(string cssFileName)
{
    var resourcePath = SimpleIoc.Default.GetInstance<IAssetPathHelper>().GetResourceFolderPath("HtmlResources", true);

    return $"<link rel=\"stylesheet\" href=\"{resourcePath}/{cssFileName}\">";
}

Summary

Using the DependencyService of Xamarin.Forms allows us once again to use platform specific functionality very easily. When we are working with WebView and HTML, this comes in handy. If you have other valid scenarios for this implementations or even ideas on how to improve them, feel free to leave a comment below or ping me on my social network accounts. Otherwise, I hope this post is helpful for some of you.

As this is the last post before xmas, I wish you all a merry xmas in addition to my traditional

Happy coding, everyone!

Posted by msicc in Android, Dev Stories, iOS, Windows, Xamarin, 1 comment
Xamarin Forms, the MVVMLight Toolkit and I: taking control over the back buttons

Xamarin Forms, the MVVMLight Toolkit and I: taking control over the back buttons

Why do I need to take control over the back button behavior?

The back button is available on Windows, Android and under certain conditions on iOS. It is one of the key navigation hooks. While the implementations vary between platforms, the functionality is always the same – go back one step in navigation. Sometimes, we need to execute actions before going back, like notifying other parts of our application or even blocking back navigation because we need to perform actions on the local page (think of a WebViewthat has internal navigation capabilities for example). While we do need only a few lines to intercept the hardware back button on Android and UWP, the software back buttons on Android and iOS need some additional code.

Xamarin.Forms – View and ViewModel implementations

Based on the code we have already written in the past posts of this series, we are already able to get events pretty easy into our ViewModel, utilizing the EventToCommandBehavior approach. To get them into our ViewModel, we will throw an own created event. You can do so pretty easy by overriding the OnBackButtonPressed()method every Xamarin.Forms pages come with:

protected override bool OnBackButtonPressed()
{
    base.OnBackButtonPressed();
    BackButtonPressed?.Invoke(this, EventArgs.Empty);
    
    //return true; //breaks navigation    
    return false; //executes navigation
}

Depending on the boolean you will return here, the back navigation will be executed or not. The next step is to pass the event into our ViewModel, like we have done already with the ViewAppearingand ViewDisappearing events before:

private void XfNavContentPage_BindingContextChanged(object sender, EventArgs e)
{
    if (this.BindingContext is XfNavViewModelBase @base)
    {
        this.Behaviors.Add(new EventToCommandBehavior()
        {
            EventName = "Appearing",
            Command = @base.ViewAppearingCommand
        });

        this.Behaviors.Add(new EventToCommandBehavior()
        {
            EventName = "Disappearing",
            Command = @base.ViewDisappearingCommand
        });

        this.Behaviors.Add(new EventToCommandBehavior()
        {
            EventName = "BackButtonPressed",
            Command = @base.BackButtonPressedCommand
        });
    }
}

As you can see from the snippet above, the next step is to add the BackButtonPressedCommandto our base ViewModel. There is nothing special on that, so here we go:

private RelayCommand _backButtonPressedCommand; 

public RelayCommand BackButtonPressedCommand =>
    _backButtonPressedCommand ?? (_backButtonPressedCommand = new RelayCommand(ExecuteBackButtonPressedCommand, CanExecuteBackButtonPressedCommand));

public virtual void ExecuteBackButtonPressedCommand() { }

public virtual bool CanExecuteBackButtonPressedCommand() 
{
    return true;
}

And that’s it, if you just want to get informed or handle back navigation on your own. However, from some of the projects I have worked on, I know that I may need to prevent back navigation. So let’s extend our code to reach that goal as well.

Blocking back navigation

Back in our base class implementation, let’s add a BindableProperty. This boolean property makes it very easy to block the back navigation (no matter if you’re doing so from a ViewModel or a View):

public static BindableProperty BlockBackNavigationProperty = BindableProperty.Create("BlockBackNavigation", typeof(bool), typeof(XfNavContentPage), default(bool), BindingMode.Default, propertyChanged: OnBlockBackNavigationChanged);

private static void OnBlockBackNavigationChanged(BindableObject bindable, object oldvalue, object newvalue)
{
    //not used in this sample
    //valid scneario would be some kind of validation or similar tasks
}

public bool BlockBackNavigation
{
    get => (bool) GetValue(BlockBackNavigationProperty);
    set => SetValue(BlockBackNavigationProperty, value);
}

The next part involves once again the already overridden OnBackButtonPressed() method. If we are blocking the back navigation, we are throwing another event:

protected override bool OnBackButtonPressed()
{
    if (this.BlockBackNavigation)
    {
        BackButtonPressCanceled?.Invoke(this, EventArgs.Empty);
        return true;
    }

    base.OnBackButtonPressed();
    BackButtonPressed?.Invoke(this, EventArgs.Empty);

    if (this.StackState.isModal) 
        return true; 
    else 
    { 
       return false; 
    }
}

Notice that I added an additional step for modal pages. Without that, the hardware button back press code will be executed twice on Android on modal pages. Of course, we are rooting also the BackButtonPressCanceledevent into our ViewModel, so let’s add it to our BindingContextChanged handler:

private void XfNavContentPage_BindingContextChanged(object sender, EventArgs e)
{
    if (this.BindingContext is XfNavViewModelBase @base)
    {
        this.Behaviors.Add(new EventToCommandBehavior()
        {
            EventName = "Appearing",
            Command = @base.ViewAppearingCommand
        });

        this.Behaviors.Add(new EventToCommandBehavior()
        {
            EventName = "Disappearing",
            Command = @base.ViewDisappearingCommand
        });

        this.Behaviors.Add(new EventToCommandBehavior()
        {
            EventName = "BackButtonPressed",
            Command = @base.BackButtonPressedCommand
        });

        this.Behaviors.Add(new EventToCommandBehavior()
        {
            EventName = "BackButtonPressCanceled",
            Command = @base.BackButtonPressCanceledCommand
        });
    }
}

To complete the code, we need to add a boolean property and the BackButtonPressCanceledCommand to our base ViewModel implementation:

private bool _blockBackNavigation;
private RelayCommand _backButtonPressCanceledCommand;

public virtual bool BlockBackNavigation
{
    get => _blockBackNavigation;

    set => Set(ref _blockBackNavigation, value);
}

public RelayCommand BackButtonPressCanceledCommand =>
    _backButtonPressCanceledCommand ?? (_backButtonPressCanceledCommand = new RelayCommand(ExecuteBackButtonPressCanceledCommand, CanExecuteBackButtonPressCanceledCommand));

public virtual void ExecuteBackButtonPressCanceledCommand() { }

public virtual bool CanExecuteBackButtonPressCanceledCommand()
{
    return true;
}

And that’s it. We already implemented everything we need in our Xamarin.Forms project.

Platform implementations

As often, we need to write some platform specific code to make our Xamarin.Forms code work in all scenarios.

Universal Windows Platform

As the Universal Windows Platforms handles the back button globally, no matter if you’re on a PC, tablet or a phone, there’s no need for additional code. Really. It’s already done with the Xamarin.Forms implementation.

Android

For the part of the hardware back button on Android devices, we are already done as well. But Android has also a software back button (eventually), which is in the toolbar (pretty similar to iOS).  There are two options we can use for Android. The first one involves just one line of code in our base page implementation’s constructor:

NavigationPage.SetHasBackButton(this, false);

This will hide the software back button on Android (and iOS as well). It would be perfectly fine on Android because all (phone and tablet) devices have a hardware back button. However, often, we do not have the possibility to go down the easy route. So let’s fully handle the toolbar button. It does not involve a lot of code, and it’s all in the MainActivity class:

protected override void OnPostCreate(Bundle savedInstanceState)
{
    var toolBar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
    SetSupportActionBar(toolBar);

    base.OnPostCreate(savedInstanceState);
}


public override bool OnOptionsItemSelected(IMenuItem item)
{
    //if we are not hitting the internal "home" button, just return without any action
    if (item.ItemId != Android.Resource.Id.Home)
        return base.OnOptionsItemSelected(item);

    //this one triggers the hardware back button press handler - so we are back in XF without even mentioning it
    this.OnBackPressed();
    // return true to signal we have handled everything fine
    return true;
}

The first step is to override the OnPostCreate method. Within the override, we are just setting the toolbar to be the SupportActionBar. If we would not do so, the more important override OnOptionsItemSelected would never get triggered. The back button in the toolbar has the internal resource name ‘Home’ (with a value of 16908332). If this button is hit, I am triggering the hardware back button press handler, which will get code execution routed back into the Xamarin.Formscode. By returning true we are telling Android we have handled this on our own. And that’s all we have to do in the Android project.

taking-over-back-button-android

iOS

On iOS,  a custom renderer for our XfNavContentPage is needed to get the same result. I was trying a few attempts that are floating around the web, but in the end this post was the most helpful to reach my goal also on iOS. Here is my version:

[assembly: ExportRenderer(typeof(XfNavContentPage), typeof(XfNavigationPageRenderer))] 
namespace XfMvvmLight.iOS.Renderer 
{ 
    public class XfNavigationPageRenderer : PageRenderer 
    { 
        public override void ViewWillAppear(bool animated) 
        { 
            base.ViewWillAppear(animated); 
  
            //making sure to use this only with non-modal pages 
            if (Element is XfNavContentPage page && this.NavigationController != null) 
            { 
                var thisPageIndex = page.Navigation.NavigationStack.IndexOf(page); 
                if (thisPageIndex >= 1) 
                { 
                    //disabling back swipe complettely: 
                    this.NavigationController.InteractivePopGestureRecognizer.Enabled = false; 
  
                    var backarrowImg = UIImage.FromBundle("arrow-back.png") 
                        .ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate); 
  
                    var backButton = new UIButton(UIButtonType.Custom) 
                    { 
                        HorizontalAlignment = UIControlContentHorizontalAlignment.Left, 
                        TitleEdgeInsets = new UIEdgeInsets(11.5f, 0f, 10f, 0f), 
                        //we need to move the image a bit more left to get closer to the OS-look 
                        ImageEdgeInsets = new UIEdgeInsets(1f, -8f, 0f, 0f) 
                    }; 
  
                    //this makes sure we use the same behavior as the OS 
                    //if there is no parent, it must throw an exception because something is wrong 
                    //with the navigation structure 
                    var parent = page.Navigation.NavigationStack[thisPageIndex - 1]; 
                    backButton.SetTitle(string.IsNullOrEmpty(parent.Title) ? "Back" : parent.Title, 
                        UIControlState.Normal); 
  
                    backButton.SetTitleColor(this.View.TintColor, UIControlState.Normal); 
                    backButton.SetImage(backarrowImg, UIControlState.Normal); 
                    backButton.SizeToFit(); 
  
                    backButton.TouchDown += (sender, e) => 
                    { 
                        if (!page.BlockBackNavigation) 
                        { 
                            this.NavigationController.PopViewController(animated); 
                        } 
                        page.SendBackButtonPressed(); 
                    }; 
  
                    backButton.Frame = new CGRect(0, 0, UIScreen.MainScreen.Bounds.Width / 4, 
                        NavigationController.NavigationBar.Frame.Height); 
  
                    var view = new UIView(new CGRect(0, 0, backButton.Frame.Width, backButton.Frame.Height)); 
                    view.AddSubview(backButton); 
  
  
                    var backButtonItem = new UIBarButtonItem(string.Empty, UIBarButtonItemStyle.Plain, null) 
                    { 
                        CustomView = backButton 
                    }; 
  
                    NavigationController.TopViewController.NavigationItem 
                        .SetLeftBarButtonItem(backButtonItem, animated); 
                } 
            } 
        } 
    } 
}

Let me explain the snippet. On iOS, we do not have direct access to the back button events in the navigation bar. We are able to override the back button, though. The first thing we have to make sure is that there is a UINavigationControlleraround. This way, we are still able to use our base page class implementation and its features for modal pages. The next step is to create a button with an image (which needs to be bundled).

Of course, we want the button’s text to behave exactly like the OS one does. That’s why we are going to get the parent view. We can easily use the current view’s NavigationStackindex for that – as long as we do not have cross navigation but a continuous one. In this case, the page before the current page is our parent. If the parent’s Titleproperty is empty, we are setting the title to “Back”, pretty much the same like the OS itself does. If you want it to be empty, just add a Title to the page with ” ” as content. This works also if you do not want your MasterPagein a Xamarin.Forms.MasterDetailPage to have a visible title, btw.

The most important thing to note is the button’s TouchDownevent – which is why we are doing this whole thing. First, we manually navigate back in iOS via the PopViewControllermethod (if necessary). After that, we are once again invoking our Xamarin.Formsimplementation via the SendBackButtonPressed method of the Xamarin.Formspage, which will then trigger our EventToCommandBehavior we implemented earlier.

The last step is to create an UIViewcontainer for the button and assign it as a UIBarButtonItemto the UINavigationController via the SetLeftBarButtonItemmethod the UINavigationItem provides. And that’s it, we now also have control over the back button on iOS.

taking-over-back-button-ios

 

Lust but not least, we need to handle also the swipe-back-gesture. This can be done the hard way by disabling the gesture completelly:

//disabling back swipe complettely:
this.NavigationController.InteractivePopGestureRecognizer.Enabled = false;

I do not have an implementation for handling that in a better way, but I will update the sample with another post in this series later on. At least I have full control over the back navigation, which is (for the moment) all I need.

As always, I hope this post will be helpful for some of you. I also updated the source code of my XfMvvmLight sample on Github to match this blog post. If you have feedback or questions, sound off below in the comments or via my social channels.

Until then, happy coding, everyone!

 

Posted by msicc in Android, Dev Stories, iOS, Windows, Xamarin, 3 comments
Why I am (once again) using an iPhone [Editorial]

Why I am (once again) using an iPhone [Editorial]

If you have been following along me for some time, you’ll probably know that I used to be a fan of Microsoft and its products (especially Windows Phone) for a long time, and I did really everything possible in the Microsoft ecosystem and promoted it whenever I was able to. Three years ago, no one – not even me –  could ever think of me using anything other than a phone with a Microsoft operating system on it.

Microsoft has changed…

The Microsoft a lot of us used to love is gone. It all started to become really bad for Windows Phone/10 Mobile when Steve Ballmer left the building (aka stepped down as CEO). He was the force behind all mobile efforts, and I think Windows Phone/Windows 10 Mobile would still exist with shiny new devices. However, Mr. Nadella is now the CEO of Microsoft. And as he stated recently in his book (“Hit Refresh”), he never understood why there should be another mobile OS besides iOS and Android (we all know duopoly is as bad as monopoly). All of his actions in the last few years, starting to burn out Nokia from Microsoft and also killing Windows 10 Mobile (even if he never would state that publicly), make sense after knowing this. Nadella’s Microsoft is a business oriented, cloud focused money machine with no more consumer love. Sure, they still have products for the consumer like Groove Music, but they do lack their consumer focus which we all enjoyed when Windows Phone started.

To sum it up, times have changed. The first steps outside the Microsoft ecosystem happened quite some time ago, you can read more on that topic right here:

Editorial: Why the app gap on Windows Phone/10 Mobile is a bigger problem than I thought

After that, I used and reviewed some Android devices for a German news site, and got back into the Android ecosystem by putting some apps (at least as beta) into the Play Store. After more than one year on Android, I see that fragmentation is still the biggest problem out there. It makes developing apps for it a mess, as there are tons of devices that do not behave like you expect when developing with a Nexus or any other plain Google device.

Software updates

Another point which is quite important, is the actuality of software updates. Due to the fragmentation problem and the ability for OEMs to change the whole user experience on Android, this has always been a problem. Google tries to address this problem with the latest Android Version Oreo, but this will not help with all those existing devices on the market that are running Marshmallow or Nougat. Even this year’s flagships are not able to catch up and profit from the new way to handle software updates. I do see a chance that this will change over the next year(s). However, this makes me to not want to spent any money on a recent Android device.

Google’s Pixel (and at least their Nexus 5X/6P) devices are certainly well built, and have a guarantee for getting the latest software updates first. However, they do not want to make me spend my money on them (not even the rumored second incarnation).  Then there is Samsung, which makes premium devices, but my experience with their smartphone has always ended bad – not only for myself, but also along my family and friends.

iOS however is kind of similar to Windows (Phone). iOS devices always get the most recent software, including bug fixes and security updates, because of the closed ecosystem. Their hardware is always from top quality. Even if they are no longer innovating like they did years ago, all features they have are very well implemented. Also, Apple supports their older devices over a long distance, which makes an iPhone a worthier device to invest money in than any Android device – especially in those devices that try to play in the same league like Apple does in terms of prices.

What’s missing?

That’s the point where I was already heavily surprised when I switched to Android. The fact that all those official apps are available on Android and iOS, does indeed make a huge difference. Some apps do have Widgets (on both Android and iOS). Sure, they are no live tiles, but those that I am using do their job in a similar good way, even if I have to swipe to left or right to get them.  On top of that, all Microsoft apps are also available on these two platforms, and most of them do actually work a lot better there than they do on their own OS. So more than a year away from Windows 10 Mobile, I do miss… nothing.

In the end…

… this was a personal decision. I was evangelizing Windows Phone and all other Microsoft products for years, as some of you may know. As they do no longer offer a valid mobile device and are not even able to get close to what Android and iOS have to offer in their ecosystems, I cannot continue to do this. I was on Android for quite some time, but in the end, I decided to go back to the iPhone, which I left a few years ago – you already read the reasons if you reached this point.

Maybe some of you felt the same way I did when moving away from Windows Phone/Windows 10 Mobile? Feel free to start a discussion here in the comments or on social media.

Until the next time, have fun!

Posted by msicc in Editorials, 0 comments
Xamarin Forms, the MVVMLight Toolkit and I: EventToCommandBehavior

Xamarin Forms, the MVVMLight Toolkit and I: EventToCommandBehavior

Often, we want to/need to know when views throw certain events. However, due to using the MVVM pattern, our application logic is separated from the view. There are several ways to get those events into our ViewModel while keeping it separated from the views. One of those is using an interface, which I showed you already in my blog post about navigation in Xamarin.Forms with MVVMLight.

Another way is the good old EventToCommand approach. Some of you might have used this approach already in WPF and other .NET applications. Xamarin.Forms has them too, this post will show you how to implement it.

Xamarin.Forms Behaviors

In Windows applications like WPF or UWP, we normally use the Interactivity namespace to use behaviors. Xamarin.Forms however has its own implementation, so we need to use the Behavior and Behavior<T> classes. All controls that derive from View are providing this BindableProperty, so we can use Behaviors in a lot of scenarios. Until the new XAML Standard is finally defined, we have to deal with this.

EventToCommandBehavior

Xamarin provides a nearly ready-to-use EventToCommandBehavior implementation and an quite detailed explanation (which is why I won’t go into details on that). The implementation has two part – the BehaviorBase<T>implementation and the EventToCommandBehavior implementation itself.

While we are able to use the BehaviorBase<T> implementation as is, we have to do some minor changes to the EventToCommandBehavior to enable a few more usage scenarios.

The first change we need to make is to derive Xamarin’s EventToCommandBehavior sample from VisualElement instead of View. This way, we can also use the behavior on controls that do not derive from View, especially in Pages. Pages do not derive from View, but they do from VisualElement (like Viewdoes, too). You need to change the Type also on the parameter of the OnAttachedTo and OnDetachingFrom methods in this case (which are the other two changes we need to do).

The rest of the implementation is basically the same like in the Xamarin sample and works quite well.

To show you a simple sample in Action, we are using the Appearing and Disappearing events to attach them via the behavior into our ModalPageViewModelon the ModalPage we integrated before. This way, you won’t need the IViewEventBrokerService I showed you in my post on navigation and modal pages. It is up to you to choose the way you want to go along, both ways are fully respecting the MVVM pattern.

Implementation

The implementation has two parts. As we want to handle the events in a Command, the first step to take is to implement two Commands in the corresponding ViewModel. I am using a base implementation (in my apps and also in this sample), so I am going to implement the Commands there. This way, every derived ViewModel can bind to this Command. Additionally, I am using a Execute...Command method and a CanExecute boolean method, which can both be overriden in derived ViewModels to implement the code to execute. Let’s have a look at the code:

public RelayCommand ViewAppearingCommand => _viewAppearingCommand ?? (_viewAppearingCommand = new RelayCommand(ExecuteViewAppearingCommand, CanExecuteViewAppearingCommand));

public virtual void ExecuteViewAppearingCommand()
{

}

public virtual bool CanExecuteViewAppearingCommand()
{
    return true;
}

public RelayCommand ViewDisappearingCommand => _viewDisappearingCommand ?? (_viewDisappearingCommand = new RelayCommand(ExecuteViewDisappearingCommand, CanExecuteViewDisappearingCommand));

public virtual void ExecuteViewDisappearingCommand()
{

}

public virtual bool CanExecuteViewDisappearingCommand()
{
    return true;
}

The second part is the XAML part, which includes the Binding to the Command properties we just created. The implementation is as easy as these four lines for both events:

    <baseCtrl:XfNavContentPage.Behaviors>
        <behaviors:EventToCommandBehavior EventName="Appearing" Command="{Binding ViewAppearingCommand}"></behaviors:EventToCommandBehavior>
        <behaviors:EventToCommandBehavior EventName="Disappearing" Command="{Binding ViewDisappearingCommand}"></behaviors:EventToCommandBehavior>
    </baseCtrl:XfNavContentPage.Behaviors>

That’s it, if you want to attach the behavior only for individual Pages. If you have a base page implementation like I do however, you can automatically attach the event already there to have it attached to all pages:

private void XfNavContentPage_BindingContextChanged(object sender, EventArgs e)
{
    if (this.BindingContext is XfNavViewModelBase)
    {
        this.Behaviors.Add(new EventToCommandBehavior()
        {
            EventName = "Appearing",
            Command = ((XfNavViewModelBase)this.BindingContext).ViewAppearingCommand
        });
 
        this.Behaviors.Add(new EventToCommandBehavior()
        {
            EventName = "Disappearing",
            Command = ((XfNavViewModelBase)this.BindingContext).ViewDisappearingCommand
        });
    }
}

I am attaching the behaviors only if the BindingContextdoes derive from my XfNavViewModelBase. The Command can be set directly in this case, without the need to use the SetBinding method.

These few lines are connecting the Event to the Command, the only thing we need to do is to override the base implementations of the “Execute…Command” methods:

public override async void ExecuteViewAppearingCommand()
{
    base.ExecuteViewAppearingCommand();
    await _dialogService.ShowMessageAsync(this.CorrespondingViewKey, $"from overriden {nameof(ExecuteViewAppearingCommand)}");
}
 
public override async void ExecuteViewDisappearingCommand()
{
    base.ExecuteViewDisappearingCommand();
    await _dialogService.ShowMessageAsync(this.CorrespondingViewKey, $"from overriden {nameof(ExecuteViewDisappearingCommand)}");
}

The above overrides are using the IDialogService you will find in the sample application to show a simple message from which overriden Execute...Command method they are created from.

Converting EventArgs to specific types

Xamarin.Forms has only a few events that have usefull EventArgs. At the time of writing this post, I tried to find valid scenarios where we want to get some things of the events to attach also an IValueConverterimplementation to get this data out of them. Fact is, the only one I ever used is the one from the Xamarin sample – which is a converter that gets the selected Item for a ListView. Because Xamarin.Forms Views already provide most of the properties I ever needed, I was able to solve everything else via Binding. To make this post complete, you can have a look into Xamarin’s sample implementation here.

Conclusion

Hooking into events on the view side of our applications can be done in several ways. It is up to you to choose the route you want to go. With this post, I showed you a second way to achieve this.

If you have some more valid scenarios for using the EventToCommandBehaviorwith a Converter that cannot be solved via Binding directly, I would love to hear them. Feel free to leave a comment here or via social networks. Of course, I updated the sample on Github with the code from this post.

As always, I hope this post is helpful for some of you. Until the next post, happy coding!

Posted by msicc in Android, Dev Stories, iOS, Windows, Xamarin, 3 comments
Xamarin Forms, the MVVMLight Toolkit and I: showing dialog messages

Xamarin Forms, the MVVMLight Toolkit and I: showing dialog messages

In this post, I will show you how to display dialog messages (also known as message box). This time, we will use again native implementations (like in the second post about Dependency Injection) to get the job done. I could have used the Xamarin.Forms Page.DisplayAlertmethod, but that one does not allow a lot of customization, so I went down to implement it my way.

Like always, the interface dictates functionality

Because of the Xamarin Forms code being a portable class library, we need an new interface that can be called from all three platforms. I am covering four scenarios which I use frequently in my apps:

public interface IDialogService
{
    void CloseAllDialogs();

    Task ShowMessageAsync(string title, string message);

    Task ShowErrorAsync(string title, Exception error, string buttonText, Action<bool> closeAction, bool cancelableOnTouchOutside = false, bool cancelable = false);

    Task ShowMessageAsync(string title, string message, string buttonText, Action<bool> closeAction, bool cancelableOnTouchOutside = false, bool cancelable = false);

    Task ShowMessageAsync(string title, string message, string buttonConfirmText, string buttonCancelText, Action<bool> closeAction, bool cancelableOnTouchOutside = false, bool cancelable = false);
}

Of course, I want to display those message dialogs asynchronously, that’s why I wrap them in a Task. Let’s have a look into the implementation:

Android

List<AlertDialog> _openDialogs = new List<AlertDialog>();

public void CloseAllDialogs()
{
    foreach (var dialog in _openDialogs)
    {
        dialog.Dismiss();
    }
    _openDialogs.Clear();
}


public async Task ShowMessageAsync(string title, string message)
{
    await Task.Run(() => ShowAlert(title, message, "OK", null, null, false, false));
}


public async Task ShowErrorAsync(string title, Exception error, string buttonText, Action<bool> callback, bool cancelableOnTouchOutside = false, bool cancelable = false)
{
    await Task.Run(() => ShowAlert(title, error.ToString(), buttonText, null, callback, cancelableOnTouchOutside, cancelable));
}

public async Task ShowMessageAsync(string title, string message, string buttonText, Action<bool> callback, bool cancelableOnTouchOutside = false, bool cancelable = false)
{
    await Task.Run(() => ShowAlert(title, message, buttonText, null, callback, cancelableOnTouchOutside, cancelable));
}


public async Task ShowMessageAsync(string title, string message, string buttonConfirmText, string buttonCancelText, Action<bool> callback, bool cancelableOnTouchOutside = false, bool cancelable = false)
{
    await Task.Run(() => ShowAlert(title, message, buttonConfirmText, buttonCancelText, callback, cancelableOnTouchOutside, cancelable));
}


I am tunneling the defined Tasks of the interface via a call to Task.Run()  into one single method call that is able to handle all scenarios I want to support. Let’s have a look at the ShowAlert method:

internal void ShowAlert(string title, string content, string confirmButtonText = null, string cancelButtonText = null, Action<bool> callback = null, bool cancelableOnTouchOutside = false, bool cancelable = false)
{
    var alert = new AlertDialog.Builder(Forms.Context);
    alert.SetTitle(title);
    alert.SetMessage(content);

    if (!string.IsNullOrEmpty(confirmButtonText))
    {
        alert.SetPositiveButton(confirmButtonText, (sender, e) =>
        {
            callback?.Invoke(true);
            _openDialogs.Remove((AlertDialog)sender);
        });
    }

    if (!string.IsNullOrEmpty(cancelButtonText))
    {
        alert.SetNegativeButton(cancelButtonText, (sender, e) =>
        {
            callback?.Invoke(false);
            _openDialogs.Remove((AlertDialog)sender);
        });
    }

    Device.BeginInvokeOnMainThread(() =>
    {
        var dialog = alert.Show();
        _openDialogs.Add(dialog);
        dialog.SetCanceledOnTouchOutside(cancelableOnTouchOutside);
        dialog.SetCancelable(cancelable);

        if (cancelableOnTouchOutside || cancelable)
        {
            dialog.CancelEvent += (sender, e) =>
            {
                callback?.Invoke(false);
                _openDialogs.Remove((AlertDialog)sender);
            };
        }


    });
}

In the first three lines I am setting up a new AlertDialog , taking into account the actual Xamarin.Forms.Context, setting the title and the message content. If no other option is used, this shows just with the standard “OK”-Button to close the message.

Often we want to modify the button text, that’s where the confirmButtonText and cancelButtonTextoverloads are being used. I am also using a callback method that takes a Boolean to show which button on the message was pressed. Showing the Dialog needs to be done on the main UI Thread. Xamarin Forms provides the Device.BeginInvokeOnMainThread method to dispatch the code within the action into the right place.

I am showing the dialog while keeping a reference in the _openDialogs List. This reference is removed once the matching button or cancel action is executed. If the message is allowed to be dismissed via outside touches or other cancel methods, this happens in the CancelEvent Eventhandler delegate I am attaching.

The implementation also has a way to close all open dialogs, but it is a good practice to have only one open at a time, especially as other platforms do support only one open dialog at a time.

UWP

Microsoft recommends to use the ContentDialog class to show messages and dialogs of all kind. So this is what we will use to show our dialog messages. Like on Android, we need a Task.Run()wrapper to make the implementation async.

List<ContentDialog> _openDialogs = new List<ContentDialog>(); 
  
  
public void CloseAllDialogs() 
{ 
    foreach (var dialog in _openDialogs) 
    { 
        dialog.Hide(); 
    } 
    _openDialogs.Clear(); 
} 
  
  
public async Task ShowErrorAsync(string title, Exception error, string buttonText, Action<bool> closeAction, bool cancelableOnTouchOutside = false, bool cancelable = false) 
{ 
    await Task.Run(() => { ShowContentDialog(title, error.ToString(), buttonText, null, closeAction, cancelableOnTouchOutside, cancelable); }); 
} 
  
public async Task ShowMessageAsync(string title, string message) 
{ 
    await Task.Run(() => { ShowContentDialog(title, message, "OK", null, null, false, false); }); 
} 
  
public async Task ShowMessageAsync(string title, string message, string buttonText, Action<bool> closeAction, bool cancelableOnTouchOutside = false, bool cancelable = false) 
{ 
    await Task.Run(() => { ShowContentDialog(title, message, buttonText, null, closeAction, cancelableOnTouchOutside, cancelable); }); 
} 
  
public async Task ShowMessageAsync(string title, string message, string buttonConfirmText, string buttonCancelText, Action<bool> closeAction, bool cancelableOnTouchOutside = false, bool cancelable = false) 
{ 
    await Task.Run(() => { ShowContentDialog(title, message, buttonConfirmText, buttonCancelText, closeAction, cancelableOnTouchOutside, cancelable); }); 
} 
  

Even if UWP allows only one ContentDialog to be open, we are using the list of open dialogs to be able to close “them” for compatibility reasons. The next step to implement is the ShowContentDialog Task all methods above are using:

internal void ShowContentDialog(string title, string content, string confirmButtonText = null, string cancelButtonText = null, Action<bool> callback = null, bool cancelableOnTouchOutside = false, bool cancelable = false) 
{ 
    Device.BeginInvokeOnMainThread(async () => 
    { 
        var messageDialog = new ContentDialog() 
        { 
            Title = title, 
            Content = content,                     
        }; 
  
  
    if (!string.IsNullOrEmpty(confirmButtonText)) 
    { 
  
        if (string.IsNullOrEmpty(cancelButtonText)) 
        { 
            messageDialog.CloseButtonText = confirmButtonText; 
  
            messageDialog.CloseButtonClick += (sender, e) => 
            { 
                callback?.Invoke(true); 
                _openDialogs.Remove((ContentDialog)sender); 
            }; 
        } 
        else 
        { 
            messageDialog.PrimaryButtonText = confirmButtonText; 
  
            messageDialog.PrimaryButtonClick += (sender, e) => 
            { 
                callback?.Invoke(true); 
                _openDialogs.Remove((ContentDialog)sender); 
            }; 
  
        } 
    } 
  
        if (!string.IsNullOrEmpty(cancelButtonText)) 
        { 
            messageDialog.CloseButtonText = cancelButtonText; 
  
            messageDialog.CloseButtonClick += (sender, e) => 
            { 
                callback?.Invoke(false); 
                _openDialogs.Remove((ContentDialog)sender); 
            }; 
        } 
  
  
  
        _openDialogs.Add(messageDialog); 
  
        await messageDialog.ShowAsync(); 
    }); 
} 

The setup of the dialog is kind of similar to android. First, we are creating a new dialog setting the title and the message.

The second part is a bit more complex here. Dialogs should hook into the CloseButton properties and events in all cases, at least after OS-Version 1703 (Creators Update). This way, the CloseButtonClickevent is also raised when the user presses the ESC-Button, the system back button, the close button of the dialog as well as the B-Button on the Xbox-Controller.

When we have only one button to show, our confirmButtonText is directed to the CloseButton, otherwise to the PrimaryButton. In the second case, the CloseButtonis connected with the cancelButtonText. We are using the same callback Action as on Android, where the bool parameter indicates which button was pressed.

In the UWP implementation the additional parameters cancelableOnTouchOutsideand cancelableare not used.

iOS

The base implementation on iOS is basically the same like on Android and UWP. In case of iOS, we are using the UIAlertController class, which is mandatory since iOS 8.

List<UIAlertController> _openDialogs = new List<UIAlertController>();

public void CloseAllDialogs()
{
    foreach (var dialog in _openDialogs)
    {
        Device.BeginInvokeOnMainThread(() =>
        {
            dialog.DismissViewController(true, null);
        });
    }
    _openDialogs.Clear();
}

public async Task ShowErrorAsync(string title, Exception error, string buttonText, Action<bool> closeAction, bool cancelableOnTouchOutside = false, bool cancelable = false)
{
    await Task.Run(() => { ShowAlert(title, error.ToString(), buttonText, null, closeAction, cancelableOnTouchOutside, cancelable); });
}

public async Task ShowMessageAsync(string title, string message)
{
    await Task.Run(() => { ShowAlert(title, message, "OK", null, null, false, false); });
}

public async Task ShowMessageAsync(string title, string message, string buttonText, Action<bool> closeAction, bool cancelableOnTouchOutside = false, bool cancelable = false)
{
    await Task.Run(() => { ShowAlert(title, message, buttonText, null, closeAction, cancelableOnTouchOutside, cancelable); });
}

public async Task ShowMessageAsync(string title, string message, string buttonConfirmText, string buttonCancelText, Action<bool> closeAction, bool cancelableOnTouchOutside = false, bool cancelable = false)
{
    await Task.Run(() => { ShowAlert(title, message, buttonConfirmText, buttonCancelText, closeAction, cancelableOnTouchOutside, cancelable); });
}

Now that we have the Task wrappers in place, we need to implement the ShowAlert method:

internal void ShowAlert(string title, string content, string confirmButtonText = null, string cancelButtonText = null, Action<bool> callback = null, bool cancelableOnTouchOutside = false, bool cancelable = false)
{
    //all this code needs to be in here because UIKit demands the main UI Thread
    Device.BeginInvokeOnMainThread(() =>
    {
        var dialogAlert = UIAlertController.Create(title, content, UIAlertControllerStyle.Alert);

        var okAction = UIAlertAction.Create(!string.IsNullOrEmpty(confirmButtonText) ? confirmButtonText : "OK", UIAlertActionStyle.Default, _ =>
        {
            callback?.Invoke(true);
            _openDialogs.Remove(dialogAlert);
        });
        dialogAlert.AddAction(okAction);


        if (!string.IsNullOrEmpty(cancelButtonText))
        {
            var cancelAction = UIAlertAction.Create(cancelButtonText, UIAlertActionStyle.Cancel, _ =>
            {
                callback?.Invoke(false);
                _openDialogs.Remove(dialogAlert);
            });
            dialogAlert.AddAction(cancelAction);
        }
        _openDialogs.Add(dialogAlert);

        var rootController = UIApplication.SharedApplication.KeyWindow.RootViewController;

        rootController.PresentViewController(dialogAlert, true, null);
    });
}

What I am doing here is straight forward – I am setting up a new UIAlertController instance via its creation method, telling it to be styled as an alert. Then I need to create two UIAlertAction instances, one for the confirmButtonText and one for the cancelButtonText.  Of course, I am hooking up the prior defined callback action, which will inform the Xamarin.Forms class about the result of the dialog.

To display the Alert, we need a reference to the RootViewController of the iOS application. In most Xamarin.Forms applications, the above code will do the job to present the UIAlertController via the PresentViewController method provided by the OS. Like the UWP implementation, also the iOS implementation needs to be executed in the main UI thread, because the UIKit demands it. That’s why also here, the whole code is running inside the Device.BeginInvokeOnMainThread method’s action delegate.

The additional parameters cancelableOnTouchOutsideand cancelableare not used on iOS.

Updating our ViewModelLocator

If you have read my post on Dependency Injection, you might remember that we are able to combine the power of MVVMLight with Xamarin.Forms own DependencyService. This is what we will do once again in our ViewModelLocator in the RegisterServices method:

var dialogService = DependencyService.Get<IDialogService>();
SimpleIoc.Default.Register<IDialogService>(() => dialogService);

And that’s already all we need to do here. Really.

Finally: Showing message dialogs

I added three buttons to the sample’s main page. One shows a simple message, one shows the exception that I manually throw and the last one provides a two choice dialog. Let’s have a quick look at the commands bound to them:

 
private RelayCommand _showMessageCommand; 
  
public RelayCommand ShowMessageCommand => _showMessageCommand ?? (_showMessageCommand = new RelayCommand(async () => 
{ 
    await SimpleIoc.Default.GetInstance<IDialogService>().ShowMessageAsync("Cool... ?", "You really clicked this button!"); 
}));

This shows a simple message without using the additional parameters. I use this one primarily for confirmations.

private RelayCommand _showErrorWithExceptionCommand;

public RelayCommand ShowErrorWithExceptionCommand => _showErrorWithExceptionCommand ?? (_showErrorWithExceptionCommand = new RelayCommand(async () =>
{
    try
    {
        throw new NotSupportedException("You tried to fool me, which is not supported!");
    }
    catch (Exception ex)
    {
        await SimpleIoc.Default.GetInstance<IDialogService>().ShowErrorAsync("Error", ex, "Sorry",
            returnValue =>
            {
                Debug.WriteLine($"{nameof(ShowErrorWithExceptionCommand)}'s dialog returns: {returnValue}");
            }, false, false);
    }
}));

This one takes an exception and shows it on the screen. I use them mainly for developing purposes.

private RelayCommand _showSelectionCommand;

public RelayCommand ShowSelectionCommand => _showSelectionCommand ?? (_showSelectionCommand = new RelayCommand(async () =>
{

    await SimpleIoc.Default.GetInstance<IDialogService>().ShowMessageAsync("Question:",
        "Do you enjoy this blog series about MVVMLight and Xamarin Forms?", "yeah!", "nope", async returnvalue =>
        {
            if (returnvalue)
            {
                await SimpleIoc.Default.GetInstance<IDialogService>()
                    .ShowMessageAsync("Awesome!", "I am glad you like it");
            }
            else
            {
                await SimpleIoc.Default.GetInstance<IDialogService>()
                    .ShowMessageAsync("Oh no...", "Maybe you could send me some feedback on how to improve it?");
            }
        },
        false, false);

}));

This one provides a choice between two options. A good example where I use this is when there is no internet connection and I ask the user to open the WiFi settings or cancel. In the sample, I am also showing another simple message after one of the buttons has been pressed. The content of this simple message depends on which button was clicked.

Action, please!

This slideshow requires JavaScript.

 

Using Xamarin.Forms’ DependencyServicetogether with the SimpleIoc implementation of MVVMLight, we are once again easily able to connect platform specific code to our Xamarin.Forms project. Every platform implementation follows the dialog recommendations and is executed using the native implementations while keeping some options open to use different kind of message dialogs.

As always, I hope this post is helpful for some of you. Until the next post, happy coding!

Posted by msicc in Android, Dev Stories, iOS, Windows, Xamarin, 1 comment
Xamarin Forms, the MVVMLight Toolkit and I: Dependecy Injection

Xamarin Forms, the MVVMLight Toolkit and I: Dependecy Injection

Recap

Let’s just do a small recap what Dependency Injection means. The DI pattern’s main goal is to decouple objects and their dependencies. To separate concerns, we are using this structure nearly every time:

  • interface which defines the provided functionality
  • service class which provides the functionality defined in the interface
  • container that allows client classes/objects to use the functionality defined in the interface

The interface, our helpful dictator

DI always involves an interface, which dictates the functionality of the implementation. In Xamarin Forms, the interface rests inside the PCL/common project:

public interface IOsVersionService
{
    string GetOsVersion { get; } 
}

This interface gets the current installed version of the operating system. The next step ist to create the platform implementation, which is commonly defined as a service class.

Platform Implementation (service class)

We need to implement the service class for each platform. The setup is pretty easy, just add a new class and implement the interface for each platform:

implement-interface-vs2017

Tip: I am using a separate folder for platform implementations and set it to be a namespace provider. This makes it easier to maintain and I keep the same structure in all platform projects.

Let’s have a look into the specific implementations:

Android

public string GetOsVersion
{
    get
    {
        var versionNb = Build.VERSION.Release;
        var codename = Build.VERSION.Codename;
 
        return $"Android {versionNb} ({codename})";
    }
}

iOS

public string GetOsVersion
{
    get
    {
        try
        {
            return $"iOS {UIDevice.CurrentDevice.SystemVersion} ({UIDevice.CurrentDevice.UserInterfaceIdiom})";
 
        }
        catch
        {
            return "This demo supports iOS only for the moment";
        }
    }
}

Windows

public string GetOsVersion
{
    get
    {
        var currentOS = AnalyticsInfo.VersionInfo.DeviceFamily;
 
        var v = ulong.Parse(AnalyticsInfo.VersionInfo.DeviceFamilyVersion);
        var v1 = (v & 0xFFFF000000000000L) >> 48;
        var v2 = (v & 0x0000FFFF00000000L) >> 32;
        var v3 = (v & 0x00000000FFFF0000L) >> 16;
        var v4 = v & 0x000000000000FFFFL;
        var versionNb = $"{v1}.{v2}.{v3}.{v4}";
 
        return $"{currentOS} {versionNb} ({AnalyticsInfo.DeviceForm})";
    }
}

Now that we are able to fetch the OS Version, we need to make the implemation visible outside of the platform assemblies. On Android and iOS, this one is pretty straigt forward by adding this Attribute on top of the class:

[assembly: Xamarin.Forms.Dependency(typeof(OsVersionService))]

Because Universal Windows projects compile differently, we need to go a different route on Windows. To make the implementation visible, we need to explicit declare the class as an assembly to remain included first (otherwise the .NET Toolchain is likely to strip it away):

protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    //other code for initialization, removed for readabilty
 
    //modified for .NET Compile
    List<Assembly> assembliesToInclude = new List<Assembly>();
    assembliesToInclude.Add(typeof(OsVersionService).GetTypeInfo().Assembly);

    Xamarin.Forms.Forms.Init(e, assembliesToInclude); 
}

Now that we have our platform implementations in place, we can go ahead and use the interface to get the OS versions.

Xamarin Forms DependencyService

With the static DependencyService class, Xamarin Forms provides a static container that is able to resolve interfaces to their native platform implementations. Using it is, once again, pretty straight forward:

private string _osVersionViaDs;
public string OsVersionViaDs
{
    get { return _osVersionViaDs; }
    set { Set(ref _osVersionViaDs, value); }
}
 
private RelayCommand _getOSVersionViaDsCommand;
 
public RelayCommand GetOsVersionViaDsCommand => _getOSVersionViaDsCommand ?? (_getOSVersionViaDsCommand = new RelayCommand(() =>
{
    OsVersionViaDs = DependencyService.Get().GetOsVersion; 
}));

In my sample application, I am using a button that fetches the OS version via Xamarin Forms DependencyService and display it into a label in my view.

Special case UWP, once again

To make this acutally work in an UWP application, we need to register the Service manually. Xamarin recommends to do so in the OnLaunched event, after Xamarin Forms is initialized:

//in OnLaunched event (App.xaml.cs)
//manually register for DependencyService 
//AFTER Forms is initialized but BEFORE VMLocator is initialized:
Xamarin.Forms.DependencyService.Register<OsVersionService>();

Only with that extra line of code, it will actually work like it should. If you want to know more on the fact that UWP needs a separate solution, take a look here into the Xamarin docs.

Why use the MVVMLight Toolkit’s Ioc?

There are several reasons. First is of course, purely personal: because I am used to write code for it. But there are also technical reasons:

  • support for cunstroctor injection
  • interface implementations can have parametered constructors
  • MVVMLight supports additional features like named instances and immediate creation on registration
  • in MVVM(Light) applications, you are very likely using DI on Xamarin Forms level, anyway (like in a NavigationService)

You see, there are some (in my opinion) good reasons to use the built in Ioc of the MVVMLight Toolkit.

How to use SimpleIoc and DependencyService together

If you are not relying on the DI-System of Xamarin Forms, you will have to write a lot of code yourself to get the platform implementations. That is not necessary, though. As our ViewModelLocator normally is already part of the Xamarin Forms PCL project, it has access  to the DependencyService and can be used to get the right implementation:

//this one gets the correct service implementation from platform implementation
var osService = DependencyService.Get();
 
// which can be used to register the service class with MVVMLight's Ioc
SimpleIoc.Default.Register<IOsVersionService>(() => osService);

This works pretty well for most implementations and provides us the possibility to use all the features MVVMLight provides. The usage then matches to what we are already familiar with:

private string _osVersionViaSimpleIoc;
public string OsVersionViaSimpleIoc
{
    get { return _osVersionViaSimpleIoc; }
    set { Set(ref _osVersionViaSimpleIoc, value); }
} 
 
private RelayCommand _getOSVersionViaSimpleIocCommand;
 
public RelayCommand GetOsVersionViaSimpleIocCommand => _getOSVersionViaSimpleIocCommand ?? (_getOSVersionViaSimpleIocCommand = new RelayCommand(() =>
{
    OsVersionViaSimpleIoc = SimpleIoc.Default.GetInstance().GetOsVersion; 
}));

If you do not want (or it is not possible due to complexity) register the platform implementation directly in the ViewModelLocator, you  can go down another route. You could create a new interface in the Xamarin Forms PCL which references the interface with the platform implentation as a member. Your implementation of this new interface (in Xamarin Forms) will be responsible for the getting the instance of the platform implementation via the built in DepenencyService.

I already used both ways in my recent Xamarin projects, but I prefer the first way that I described above.

Conclusion

Due to the fact that we know the DI pattern already as we (of course) follow the MVVM pattern in our applications, there is no big mystery about using the built in DependencyService of Xamarin Forms. We can easily integrate it into the MVVMLight Toolkit and combine the best of both worlds this way.

Nonetheless, I know that also some beginners are following my posts, so I tried to describe everything a bit more extended. As always, I hope this post is helpful for some of you. In my next post, I will show you how I solved the Navigation “problem” in my Xamarin Forms applications. In the meantime, you can already have a look at the sample code on Github.

Happy coding, everyone!

Posted by msicc in Android, Dev Stories, iOS, Windows, Xamarin, 6 comments

Xamarin Forms, the MVVMLight Toolkit and I (new series) [Updated]

Updated some code parts that needed to be changed in the ViewModelLocator.

Please see also this post for upgrading the project to .netStandard:

Xamarin Forms, the MVVMLight Toolkit and I: migrating the Forms project and MVVMLight to .NET Standard



Like some of you may have already registered, I have been doing the next step and went cross platform with my personal projects. I am primarily using Xamarin Forms, because I eventually like XAML a little too much. I took a break from round about 2 years on my Xamarin usage, and I am happy to see that it has improved a lot in the meantime. While Xamarin Forms still has room for improvementes, one can do already real and serious projects with it. As I like the lightweight MVVMLight toolkit as much as I like XAML, it was a no-brainer for me to start also my recent Xamarin projects with it.

There is quite some setup stuff to do if you want get everything working from the Xamarin Forms PCL, and this post will be the first in a series to explain the way I am currently using. Some of the things I do may be against good practice for Xamarin Forms, but sometimes one has to break out of them to write code more efficiently and also maintain it easier.

Installing MVVM Light into a Xamarin Forms PCL project

Of course, we will start with a new Xamarin Forms project. After selecting the type Cross Platform App in the New Project Dialog in Visual Studio, you’ll be presented with this screen, which was introduced in the Cycle 9 Release of Xamarin:

Select Xamarin Forms as UI Technology and PCL as Code Sharing Strategy to start the solution creation. As it creates several projects, this may take some time, so you may be able to refill your coffee cup in the meantime. Once the project is created, you’ll see 4 projects:

Before we are going to write some code, we will update and add the additional packages from within the NuGet Package Manager. If your are not targeting the Android versions 7.x , Xamarin Forms is not able to use the latest Android Support libraries, so you’ll have to stick with version 23.3.0 of them (see release notes of Xamarin Forms). Since it makes sense for a new app to target the newest Android version, we’ll be updating the Android Support packages for our sample app as well.

If the NuGet Package manager demands you to restart, you’ll better follow its advise. To verify everything is ok with the updated NuGet packages, set the Android project as Startup project and let Visual Studio compile it.

If all goes well, let’s make sure we are using the right UWP compiler version for Visual Studio 2015. The .NETCORE package for the UWP needs to be of Version 5.2.x, as 5.3 is only compatible with Visual Studio 2017.

Once the packages are up to date, we’ll finally download and install MVVMLight. As we will host all of our ViewModel Logic in Xamarin Forms, together with their Views, we just need to install it into the Portable library and into the UWP project:

There will be no changes to the project except adding the reference. We need to set up the structure ourselves. First, create two new folders, View and ViewModel:

Move the MainPage into the View Folder and adjust the Namespace accordingly. The next step is to setup a ViewModelLocator class, which takes a central part of our MVVM structure. Here is what you need for the base structure:

    public class ViewModelLocator
    {
        private static ViewModelLocator _instance;
        public static ViewModelLocator Instance => _instance ?? (_instance = new ViewModelLocator());

        public void Initialize()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
            RegisterServices();        

        }

        private static void RegisterServices()
        {
            //topic of another blog post
        }

        #region ViewModels  
        #endregion

        #region PageKeys
        #endregion
    }

You may notice some things. First, I am using the singleton pattern for the ViewModelLocator to make sure I have just one instance. I had some problems with multiple instances on Android, and using a singleton class helped to fix them. The second part of the fix is to move everything that is normally in the constructor into the Initialize() method. Now let’s go ahead, add a MainViewModel to the project and to the ViewModelLocator:

        public void Initialize()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
            RegisterServices();
            if (!SimpleIoc.Default.IsRegistered)
                SimpleIoc.Default.Register<MainViewModel>();
        }

        #region ViewModels
        public MainViewModel MainVm => ServiceLocator.Current.GetInstance<MainViewModel>();
        #endregion

Let’s give the MainViewModel just one property which is not subject to change (at least for now):

public string HelloWorldString { get; private set; } = "Hello from Xamarin Forms with MVVM Light";

The next step is to get the App.xaml file code right, it should look like this:

<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             x:Class="XfMvvmLight.App" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             d1p1:Ignorable="d" 
             xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:forms="http://xamarin.com/schemas/2014/forms" 
             xmlns:vm="clr-namespace:XfMvvmLight.ViewModel" >
  <Application.Resources>
    <!-- Application resource dictionary -->
    <forms:ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
      <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
    </forms:ResourceDictionary>
  </Application.Resources>
</Application>

Now that we have set up the baisc MVVM structure, we are going to connect our MainViewModel to our MainPage. There are two ways to do so.

In Xaml:

<ContentPage.BindingContext>
    <Binding Path="MainVm" Source="{StaticResource Locator}" />
</ContentPage.BindingContext>

in Code:

        public MainPage()
        {
            InitializeComponent();

            this.BindingContext = ViewModelLocator.Instance.MainVm;
        }

After that, just use the HelloWorldString property of the MainViewModel as Text in the already existing Label:

    <Label Text="{Binding HelloWorldString}"
           VerticalOptions="Center"
           HorizontalOptions="Center" />

Before we are able to test our code, we need to make sure our ViewModelLocator is initialized properly:

Android:

    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle bundle)
        {
            //TabLayoutResource = Resource.Layout.Tabbar;
            //ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(bundle);

            global::Xamarin.Forms.Forms.Init(this, bundle);

            ViewModelLocator.Instance.Initialize();

            LoadApplication(new App());
        }
    }

iOS:

    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        //
        // This method is invoked when the application has loaded and is ready to run. In this 
        // method you should instantiate the window, load the UI into it and then make the window
        // visible.
        //
        // You have 17 seconds to return from this method, or iOS will terminate your application.
        //
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();

            ViewModelLocator.Instance.Initialize();

            LoadApplication(new App());

            return base.FinishedLaunching(app, options);
        }
    }

UWP:

//in App.xaml.cs:
        protected override void OnLaunched(LaunchActivatedEventArgs e)
        {

#if DEBUG
            if (System.Diagnostics.Debugger.IsAttached)
            {
                this.DebugSettings.EnableFrameRateCounter = true;
            }
#endif

            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (rootFrame == null)
            {
                // Create a Frame to act as the navigation context and navigate to the first page
                rootFrame = new Frame();

                rootFrame.NavigationFailed += OnNavigationFailed;

                Xamarin.Forms.Forms.Init(e);

                ViewModelLocator.Instance.Initialize();

                if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    //TODO: Load state from previously suspended application
                }

                // Place the frame in the current Window
                Window.Current.Content = rootFrame;
            }

            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                rootFrame.Navigate(typeof(MainPage), e.Arguments);
            }
            // Ensure the current window is active
            Window.Current.Activate();
        }

Let’s test our app on all platforms by building and deploying them:

Android

iOS Screenshot – post will be updated 

UWP

If you get the same screens, you are all set up to use Xamarin Forms with MVVMLight.

Conclusion

I know there are several specialized MVVM frameworks/toolkits floating around, which are commonly used for Xamarin Forms. As I am quite used to the MVVMLight toolkit, I prefer it over them. It is a lightweight solution, and I have more control over the code that is running than with the other options. I know I have to handle a lot of things in this case on my own (Navigation for example), but these will get their own blog posts. Starting with one of the future posts in this series, I will provide a sample app on my Github account.

If you have feedback or questions, feel free to get in contact with me via comments or on my social accounts. Otherwise, I hope this post and the following ones are helpful for some of you.

Happy coding, everyone!

Posted by msicc in Android, Dev Stories, iOS, Xamarin, 12 comments

Editorial: Why the app gap on Windows Phone/10 Mobile is a bigger problem than I thought

Note: as this is an editorial, this blog post reflects my own experience and thoughts. You will agree with some points, but disagree with others. Feel free to leave a comment to start a discussion below.

Recently, I received a Nexus 5x as development device for a project I am about to start. As tech enthusiast, I could not resist to start using it as my daily driver.

As you might guess, I started with an install orgy of all the apps I am using on my Lumia 950 XL and set them up. It may be surprising, but I immediately recognized huge differences between the platform versions.

Take the Facebook app for example. Animations are smooth like butter, almost all settings are in app instead of leading to a mobile page, even loading content and scrolling is a whole lot better than on Windows 10 Mobile.

Another example is the Path app. Never been updated since its launch on Windows Phone, I was truly surprised when I opened It on Android. It is an app that really is fun to use on Android. I bet they would have a lot more users on Windows if they align the app… sadly, they abanonded the platform completely a few month ago.

The last example is the WordPress app. It exists on Windows (Phone) for existing users, but the experience on Android is galaxies away from the one the one in Windows (Phone) has/had. I am even writting this post with it, because it feels just right to do this (I only did that once on Windows Phone).

These were only three examples, but they show pretty much how different official apps can be between platforms (and how they are supported). And they all show, that Windows really has no priority anywhere (sadly).
The quality of apps that are available on Windows is not all, though. Of course, I downloaded also some apps that aren’t available for my Lumia 950 XL as well. And it does make a difference.

On my Lumia, I often use the mobile page for things to do/achieve. On Android, I have a whole lot more apps to choose from, so I never had to open the browser for:

  • my mobile carrier
  • my landline & tv carrier
  • the communal page of Winterthur (where I live)
  • swiss auction page of ricardo.ch
  • swiss page tutti.ch
  • Amazon (Bonus: the apps are connected, needed to log in only on one and all others had my account)
  • eat.ch, a swiss food order service
  • Imgur
  • Giphy
  • and more…

Some say a good mobile page is as good as an app. That’s wrong for most cases. A good written app is always handier than a website. On any platform (at least in my experience).

Android app quality has improved a lot in the last two and a half years (that’s how long it took me to deeply test the OS and the ecosystem again). They are equal to the high level on iOS (which I saw also recently, as my son broke out of the Windows world I created at home).

On Windows, we have a lot of third party apps that are trying to fill the gap. I respect those developers (at least those that use legal, public APIs), but it is just not the same. And even on Android (or iOS), there is room for third party apps besides the official ones.

The Android OS itself feels also grown up, and it is difficult to say if iOS or Android are better. It is more a question of who you prefer – Google or Apple.

Microsoft’s Windows (Phone/10 Mobile) is on a good way to get on par. Lots of the functionality is also there. But… as long as the provider of a service, no matter which kind, do not use them (for whatever reason), Windows will never grow up. The Universal App approach is a good idea, and it may pay off one day – or it may be too late already. The recent switch to focus on enterprise users does not really help. Because also enterprise users tend to have only one device. And also enterprise users tend to use apps on their mobile device.

As a WinPhan, writting this honest post deeply hurts. Even more, as I really am thinking about switching platforms for mobile things. Not as a developer, but as a user (at least until Windows has grown up).

Posted by msicc in Editorials, 4 comments

Goodbye Telefónica (Germany), Hello ShareCommService (Switzerland)

Yes, you read that right. Today was my last work day at Telefónica, where I worked since June 2007. During that time, I learned a lot about how good customer service should be, and even more about mobile networks and mobile devices (phones, tablets and more). During that time, I also started my dev story in my spare time – all because there was not a single fishing knots application available for Windows Phone (read more here).

This lead to get recognized also within Telefónica as a developer, and so I was asked to concept and develop the application Friends & You (nope, you can’t download it as it is an internal app).  I learned a lot about how corporate apps aren’t that easy to concept and build during that time, as well as as how restrictive corporate rules can be. After all, I had a few challenges to complete. Thanks to Friends & You, I was also able to dive into the world of Xamarin, where I learned a lot about the application structures of Android and iOS (which will be helpful for eventually porting some of my Windows Phone apps to those two).

I want to say thanks to my colleagues, you´re awesome! Keep up the great work you´re doing in Customer Service.

Back in September then, I opened up my Twitter app and the first tweet I read was this one:

image

I opened the attached document and read the job description. As an self-thought developer, I first was about to close it and put it aside as “read and done”.

Due to the head count freeze at Telefónica after acquiring e-Plus from KPN, there are no chances to become a real full time developer within Telefónica for the next time. But that is what I want to do. After reopening the document and reading it again, I decided to get in contact with Roman Mueller (who I knew from Twitter already).

We talked about the job itself and the circumstances behind the announcement. After a few talks and a visit in Switzerland, the decision was made. I am starting the next chapter of my developer story in January, moving to Switzerland, where I will add deeper SQL knowledge, WPF and a lot more to my development knowledge.

At this point, I want to thank ShareCommService and especially Roman for all the help I received already to make this all happen and get started.

It is going to be an exciting journey for me (and my family), and we are ready to go.

Happy coding everyone!

Posted by msicc in Dev Stories, Editorials, 1 comment

Book review: iOS Development with Xamarin Cookbook (Dimitris Tavlikos)

I love to learn and expand my knowledge. Because of this, I was absolutely happy when I was asked for a book review about Dimitris’ iOS book.

The book is a huge collection of iOS recipes using Xamarin. The first three chapters are going deeply into the UI of an iOS application, looking on a lot (almost all) possible aspects of UI elements. What I like very much is that the author shows the code, usually with a step by step guide, and after that delivers a detailed explanation why something works in the way it does.

The next two chapters are all about creating and displaying data, files and sqlite, providing the same experience as the first chapters.

The sixth chapter is all about consuming services, such as web services, REST services or even WCF services (I wasn’t even aware of this being possible). Very good starting point for so many app ideas.

So far, the book shows already a lot of what we can do with Xamarin. But modern apps often contain media content: videos, photos, capturing media – this is what chapter 7 is all about.

Like all modern Smartphone operating systems, iOS provides some methods to let our apps interact with the OS. The 8th chapter is all about those interactions, like contacts, mail and more and has the matching real world scenarios.

The most usable apps use a device’s sensors, touch and gestures. Of course, with Apple being the leader in this space for a long time (we just need to be fair in this point), iOS has a lot of APIs for these. Chapter nine has some good recipes to help us with improving our app’s UX.

If your app needs location services and maps, chapter 10 is your friend. It shows you how to interact with Apple’s map services, add annotations and a lot more.

Users love when apps have some nice animations when something changes in an app. iOS provides a lot of options, and chapter 11 explains a lot about animations and drawing methods.

One of the most important parts when developing an app is lifecycle handling. As with any other OS, also iOS has its specific methods to handle the lifecycle. Background operations are part of this handling. In chapter 12, Dimitri tells us a lot about handling the states of an app as well as background operations.

Chapter 13 consists of tips and recipes for localization of an iOS app.

One of the most important steps when creating an iOS app is deploying the app. Apps should of course be tested on real devices, and this what chapter 14 is about – but not only. Also the required steps to prepare and app for submission as well as the submission to the store are explained.

The final chapter contains some additional recipes that can make your app more valuable like content sharing or text-to-speech.

Conclusion

I only began with Xamarin.iOS a few month ago. This book provides a great insight into development for iOS using the Xamarin IDE. As I said already, I like the approach of showing code first and then explaining what it does exactly and provide additional info if suitable. This book is absolutely worth every single cent if you want to start with iOS and Xamarin.

If you’re interested in the book, you’re just a click away: http://bit.ly/1tnxmGX

Note: This post was completely written on my phone. If you find typos, you can keep them ;-).

Posted by msicc in Dev Stories, iOS, Xamarin, 0 comments