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 BindablePropertyfunctionality. 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)
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.
The documentation recommends using Effects when we just want to change properties on the underlying native control. I have begun to love Effects as they make my code more readable. With Effects, I always know that there is a platform-specific implementation attached, while that is not obvious when using a custom renderer. Nowadays, I always try to implement an Effect before a Renderer.
Update: I updated the sample project to also respect changes in the ImageButton‘s source. I recently ran into the situation to change the Source (Play/Pause) via my ViewModel based on its state and realized that the effect needs to be reapplied in this case. Please be aware.
The basics
Effects work in a similar way to Renderers. You implement the definition in the Xamarin.Forms project, which attaches it to the control that needs the change. The PlatformEffect implementation needs to be exported to be compiled into the application. Like in a Renderer, the platform implementation also supports property changes. In this new series #XfEffects, I am going to show you some Effects that have been useful for me.
Effect declaration
Let’s turn over to this post’s Effect. We will change the TintColor of an ImageButton to our needs. Let’s start with creating the class for our Effect:
public class ImageButtonTintEffect : RoutingEffect
{
public ImageButtonTintEffect() : base($"XfEffects.{nameof(ImageButtonTintEffect)}")
{
}
}
All Xamarin.FormsEffect implementations need to derive from the RoutingEffect class and pass the Effect‘s name to the base class’ constructor. That’s pretty much everything we have to do for the Effect class itself.
Effect extension for passing parameters
The easiest way for us to get our desired TintColor to the platform implementation is an attached BindableProperty. To be able to attach the BindableProperty, we need a static class that provides the container for the attached property:
public static class ImageButtonTintEffectExtensions
{
public static readonly BindableProperty TintColorProperty = BindableProperty.CreateAttached("TintColor", typeof(Color), typeof(ImageButtonTintEffectExtensions), default, propertyChanged: OnTintColorPropertyChanged);
public static Color GetTintColor(BindableObject bindable)
{
return (Color)bindable.GetValue(TintColorProperty);
}
public static void SetTintColor(BindableObject bindable, Color value)
{
bindable.SetValue(TintColorProperty, value);
}
private static void OnTintColorPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
}
}
Of course, we want to set the TintColor property as Xamarin.Forms.Color as this will make it pretty easy to control the color from a Style or even a ViewModel.
We want our effect to only being invoked if we change the default TintColor value. This makes sure we are running only code that is necessary for our application:
private static void OnTintColorPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is ImageButton current)
{
if ((Color)newValue != default)
{
if (!current.Effects.Any(e => e is ImageButtonTintEffect))
current.Effects.Add(Effect.Resolve(nameof(ImageButtonTintEffect)));
}
else
{
if (current.Effects.Any(e => e is ImageButtonTintEffect))
{
var existingEffect = current.Effects.FirstOrDefault(e => e is ImageButtonTintEffect);
current.Effects.Remove(existingEffect);
}
}
}
}
Last but not least in our Xamarin.Forms application, we want to use the new Effect. This is pretty easy:
<!--import the namespace-->
xmlns:effects="clr-namespace:XfEffects.Effects"
<!--then use it like this-->
<ImageButton Margin="12,0,12,12"
effects:ImageButtonTintEffectExtensions.TintColor="Red"
BackgroundColor="Transparent"
HeightRequest="48"
HorizontalOptions="CenterAndExpand"
Source="ic_refresh_white_24dp.png"
WidthRequest="48">
<ImageButton.Effects>
<effects:ImageButtonTintEffect />
</ImageButton.Effects>
</ImageButton>
We are using the attached property we created above to provide the TintColor to the ImageButtonTintEffect, which we need to add to the ImageButton‘s Effects List.
Android implementation
Let’s have a look at the Android-specific implementation. First, let’s add the platform class and decorate it with the proper attributes to export our effect:
using Android.Content.Res;
using Android.Graphics;
using System;
using System.ComponentModel;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using AWImageButton = Android.Support.V7.Widget.AppCompatImageButton;
[assembly: ResolutionGroupName("XfEffects")]
[assembly: ExportEffect(typeof(XfEffects.Droid.Effects.ImageButtonTintEffect), nameof(XfEffects.Effects.ImageButtonTintEffect))]
namespace XfEffects.Droid.Effects
{
public class ImageButtonTintEffect : PlatformEffect
{
protected override void OnAttached()
{
}
protected override void OnDetached()
{
}
protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
{
}
}
}
Remember: the ResolutionGroupName needs to be defined just once per app and should not change. Similar to a custom Renderer, we also need to export the definition of the platform implementation and the Forms implementation to make our Effect working.
Android controls like buttons have different states. Properties on Android controls like the color can be set based on their State attribute. Xamarin.Android implements these states in the Android.Resource.Attributeclass. We define our ImageButton‘s states like this:
Good to know: certain states like ‘disabled‘ are created by just adding a ‘-‘ in front of the matching state defined in the OS states list (negating it). We need this declaration to create our own ColorStateList, which will override the color of the ImageButton‘s image. Add this method to the class created above:
private void UpdateTintColor()
{
try
{
if (this.Control is AWImageButton imageButton)
{
var androidColor = XfEffects.Effects.ImageButtonTintEffectExtensions.GetTintColor(this.Element).ToAndroid();
var disabledColor = androidColor;
disabledColor.A = 0x1C; //140
var pressedColor = androidColor;
pressedColor.A = 0x24; //180
imageButton.ImageTintList = new ColorStateList(_colorStates, new[] { androidColor.ToArgb(), disabledColor.ToArgb(), pressedColor.ToArgb() });
imageButton.ImageTintMode = PorterDuff.Mode.SrcIn;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(
$"An error occurred when setting the {typeof(XfEffects.Effects.ImageButtonTintEffect)} effect: {ex.Message}\n{ex.StackTrace}");
}
}
This code works above the Android SDK 23, as only then the ability to modify the A-channel of the defined color was added. The Xamarin.FormsImageButton translates into a AppCompatImageButton on Android. The AppCompatImageButton has the ImageTintList property. This property is of type ColorStatesList, which uses the states we defined earlier and the matching colors for those states.
Last but not least, we need to set the composition mode. If you want to get a deeper understanding of that, a great starting point is this StackOverflow question. To make things not too complicated, we are infusing the color into the image. The final step is to call the method in the OnAttached override as well as in the OnElementPropertyChanged override.
The result based on the sample I created looks like this:
iOS implementation
Of course, also on iOS, we have to attribute the class, similar to the Android version:
using System;
using System.ComponentModel;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ResolutionGroupName("XfEffects")]
[assembly: ExportEffect(typeof(XfEffects.iOS.Effects.ImageButtonTintEffect), nameof(XfEffects.Effects.ImageButtonTintEffect))]
namespace XfEffects.iOS.Effects
{
public class ImageButtonTintEffect : PlatformEffect
{
protected override void OnAttached()
{
}
protected override void OnDetached()
{
}
protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
{
}
}
}
The underlying control of the Xamarin.FormsImageButton is a default UIButton on iOS. The UIButton control has an UIImageView, which can be changed with the SetImage method. Based on that knowledge, we are going to implement the UpdateTintColor method:
private void UpdateTintColor()
{
try
{
if (this.Control is UIButton imagebutton)
{
if (imagebutton.ImageView?.Image != null)
{
var templatedImg = imagebutton.CurrentImage.ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate);
//clear the image on the button
imagebutton.SetImage(null, UIControlState.Normal);
imagebutton.ImageView.TintColor = XfEffects.Effects.ImageButtonTintEffectExtensions.GetTintColor(this.Element).ToUIColor();
imagebutton.TintColor = XfEffects.Effects.ImageButtonTintEffectExtensions.GetTintColor(this.Element).ToUIColor();
imagebutton.SetImage(templatedImg, UIControlState.Normal);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"An error occurred when setting the {typeof(ImageButtonTintEffect)} effect: {ex.Message}\n{ex.StackTrace}");
}
}
Let’s review these code lines. The first step is to extract the already attached Image as a templated Image from the UIButton‘s UIImageView. The second step is to clear the Image from the Button, using the SetImage method and passing null as UIImage parameter. I tried to leave out this step, but it does not work if you do so.
The next step changes the TintColor for the UIButton‘s UIImageView as well as for the button itself. I was only able to get the TintColor changed once I changed both TintColor properties.
The final step is to re-attach the extracted image from step one to the UIImageButton‘s UIImageView, using once again the SetImage method – but this time, we are passing the extracted image as UIImage parameter.
Of course, also here we need to call this method in the OnAttached override as well as in OnElementPropertyChanged.
The result should look similar to this one:
Conclusion
It is pretty easy to implement extended functionality with a Xamarin.Forms Effect. The process is similar to the one of creating a custom renderer. By using attached properties you can fine-tune the usage of this code and also pass property values to the platform implementations.
Please make sure to follow along for the other Effects I will post as part of this new series. I also created a sample app to demonstrate the Effects (find it on Github). As always, I hope this post will be helpful for some of you.
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:
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:
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:
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.
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.
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.
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!
I always liked how the MVVMLight Toolkit provided the NavigationService for my Windows & Windows Phone applications. That said, I tried to keep the idea of its NavigationService and ported it over to my Xamarin.Forms structure. I also extended it to fit the needs of my XF apps, for example for pushing modal pages (we’ll see that later). So for the base idea, I have to say thanks to Laurent Bugnion for the Windows platform implementation in MVVMLight and for keeping it simple. The later fact allows one to easily extend and adapt the service.
Also, there are tons of really good and also working samples around the web to show navigation in Xamarin.Forms. However, most of them follow another strategy, so I came to the point where decided to write my own implementation. My way may work for most scenarios without making a difference between navigation and showing modal pages. It provides an easy implementation and usage while following the MVVM pattern as far as it can go with Xamarin.Forms.
Components
My implementation has some key components, which I will describe briefly in this post:
Interfaces for Navigation and view events
Implementation of these interfaces
using the implementations in views
using the implementations in ViewModels
Interfaces for the win!
If we want to follow the MVVM pattern, we need to keep our Views completely separated from our ViewModels. A common practice to achieve this goal is the usage of interfaces, and so do I. If you have read my previous blog post about Dependency Injection, you know already a bit about the things we have to do. First, we will create an interface for the navigation itself:
As you can see, it is a pretty big interface that covers nearly all possible navigation scenarios of a Xamarin.Forms app (at least those that I had to deal with already). We are going to hook into a Xamarin.Forms  NavigationPage and configure our page handling cache with the configure method. As all navigation methods in Xamarin Forms are async, all navigational tasks will be implemented async as well. Additionally, we will have some helpful properties that we can use in our application implementation.
In Windows applications, we have some additional events for pages like  Loaded or OnNavigatedTo(and so on). Xamarin.Forms pages have something similar: ViewAppearing and ViewDisappearing. These two events correspond to OnNavigatedTo and OnNavigatedFrom in a Windows application. Sometimes, we need to know when those events happen in our ViewModels or other places behind the scenes to get stuff done. That’s why I created an interface for this purpose:
public interface IViewEventBrokerService
{
event EventHandler<ViewEventBrokerEventArgs> ViewAppearing;
event EventHandler<ViewEventBrokerEventArgs> ViewDisAppearing;
void RaiseViewAppearing(string pageKey, Type pageType, bool isModal);
void RaiseViewDisAppearing(string pageKey, Type pageType, bool isModal);
}
I also created my own EventArgs to make it easier to pass all data around (as you can see above). Here is the class:
public class ViewEventBrokerEventArgs : EventArgs
{
public ViewEventBrokerEventArgs(string pageKey, Type pageType, bool isModal)
{
PageKey = pageKey;
PageType = pageType;
IsModal = isModal;
}
public string PageKey { get; private set; }
public Type PageType { get; private set; }
public bool IsModal { get; private set; }
}
Now that we have our interfaces defined, we are going the next step and have a look into their implementations.
So you’re back from reading the documentation? Great, then lets have a look what our XfNavigationServiceimplementation does. It builds on top of the Xamarin.Forms NavigationPage, which implements the INavigation interface. Other solutions I saw are pulling down this interface and implement it in their implementation. I prefer to keep it simple and just use the already implemented interface in the Xamarin.Forms NavigationPage, which is mandatory for my implementation. We are pulling it into our implementation with the Initialize(NavigationPage navigationPage) method:
public void Initialize(NavigationPage navigationPage)
{
_navigationPage = navigationPage;
}
We could also use a constructor injection here. Most of the time it would work, but I had some problems to get the timing right under certain circumstances. That’s why I prefer to manually initialize it to overcome these timing problems  – and it does not really hurt in real life applications to have it a bit more under control.
Before we are going to see the actual implementation, I need to break out of this scope and explain a threading issue.
Locking the current executing thread
Often we are running a lot of code at the same time. This could bring up some issues with ourXfNavigationService. If multiple threads try to change or execute code from our interface implementation, the result may not the one we desired. To prevent this, we would normally use the lock statement to allow only one thread modifying our code. Problem with the lock statement is, that we cannot run asynchronous code within.
As asynchronous code execution removes some of the headache in programming, we need a solution for this. And there is one, utilizing the SemaphoreSlim class of the .NET framework. Basically, the SemaphoreSlim class provides a single application Semaphore implementation. Without going deeper into it, we are replacing the lock statement we would normally use with this. We just need to initialize the SemaphoreSlim class as a private static member:
//using this instead of lock statement
private static SemaphoreSlim _lock = new SemaphoreSlim(1, 1);
This will only allow one thread to access the objects we are passing after it, and before releasing it (which is our responsibility). The code itself is recommended to run in a try..finally  block (you’ll see that below). Pretty much the same thing the lock statement would do, but with the possibility to run asynchronous code.
Back to the implementation
The next step is to allow registering pages with a name and their type from the ViewModelLocator. I am doing the same as in the standard MVVMLight implementation here:
//declare private member for the registered pages cache
private readonly Dictionary<string, Type> _pagesByKey = new Dictionary<string, Type>();
public void Configure(string pageKey, Type pageType)
{
    //synchronous lock
    _lock.Wait();
    try
    {
        if (_pagesByKey.ContainsKey(pageKey))
        {
            _pagesByKey[pageKey] = pageType;
        }
        else
        {
            _pagesByKey.Add(pageKey, pageType);
        }
    }
    finally
    {
        _lock.Release();
    }
}
Once we have our pages configured (we’ll see that later in this post), we are easily able to identify our registered pages for navigation purposes. Sometimes we want to get the current Page, so we need to implement a property for that, as well as for the current page key and the current modal page key:
public Page GetCurrentPage()
{
return _navigationPage?.CurrentPage;
}
public string CurrentPageKey
{
    get
    {
        _lock.Wait();
        try
        {
            if (_navigationPage?.CurrentPage == null)
            {
                return null;
            }
Â
            var pageType = _navigationPage.CurrentPage.GetType();
Â
            return _pagesByKey.ContainsValue(pageType)
                ? _pagesByKey.First(p => p.Value == pageType).Key
                : null;
        }
        finally
        {
            _lock.Release();
        }
    }
}
public string CurrentModalPageKey
{
    get
    {
        _lock.Wait();
Â
        try
        {
            if (ModalStackCount == 1)
            {
                return null;
            }
Â
            //only INavigation holds the ModalStack
            var pageType = _navigationPage.Navigation.ModalStack.Last().GetType();
Â
            return _pagesByKey.ContainsValue(pageType) ? _pagesByKey.FirstOrDefault(p => p.Value == pageType).Key
                : null;
        }
        finally
        {
            _lock.Release();
        }
    }
}
I found myself in situations where I needed to check if I am on a modal page, so lets add a method for that:
public (bool isRegistered, bool isModal) StackContainsNavKey(string pageKey)
{
Â
    bool isUsedModal = false;
    bool isRegistered = false;
Â
    _lock.Wait();
    try
    {
        isRegistered = _pagesByKey.ContainsKey(pageKey);
Â
Â
        if (isRegistered)
        {
            var pageType = _pagesByKey.SingleOrDefault(p => p.Key == pageKey).Value;
Â
            var foundInNavStack = _navigationPage.Navigation.NavigationStack.Any(p => p.GetType() == pageType);
            var foundInModalStack = _navigationPage.Navigation.ModalStack.Any(p => p.GetType() == pageType);
Â
            if (foundInNavStack && !foundInModalStack || !foundInNavStack && !foundInModalStack)
            {
                isUsedModal = false;
            }
            else if (foundInModalStack && !foundInNavStack)
            {
                isUsedModal = true;
            }
            else
            {
                throw new NotSupportedException("Pages should be used exclusively Modal or for Navigation");
            }
        }
        else
        {
            throw new ArgumentException($"No page with key: {pageKey}. Did you forget to call the Configure method?", nameof(pageKey));
        }
    }
    finally
    {
        _lock.Release();
    }
Â
    return (isRegistered, isUsedModal);
}
This method checks if a page is registered correctly with its key and if it is presented modal at the moment. It also makes sure that an exception is thrown if a page is used modal AND in a navigation flow, which I think is a good practice to avoid problems when using the service. Finally, let’s add a Task for navigation to another page:
public async Task NavigateToAsync(string pageKey, object parameter, bool animated = true)
{
    await _lock.WaitAsync();
Â
    try
    {
Â
        if (_pagesByKey.ContainsKey(pageKey))
        {
            var type = _pagesByKey[pageKey];
            ConstructorInfo constructor = null;
            object[] parameters = null;
Â
            if (parameter == null)
            {
                constructor = type.GetTypeInfo()
                    .DeclaredConstructors
                    .FirstOrDefault(c => !c.GetParameters().Any());
Â
                parameters = new object[]
                {
                };
            }
            else
            {
                constructor = type.GetTypeInfo()
                    .DeclaredConstructors
                    .FirstOrDefault(
                        c =>
                        {
                            return c.GetParameters().Count() == 1
                                   && c.GetParameters()[0].ParameterType == parameter.GetType();
                        });
Â
                parameters = new[] { parameter };
            }
Â
            if (constructor == null)
            {
                throw new InvalidOperationException("No constructor found for page " + pageKey);
            }
Â
            var page = constructor.Invoke(parameters) as Page;
            if (_navigationPage != null)
            {
                Device.BeginInvokeOnMainThread(async () =>
                {
                    await _navigationPage.Navigation.PushAsync(page, animated);
                });
            }
            else
            {
                throw new NullReferenceException("there is no navigation page present, please check your page architecture and make sure you have called the Initialize Method before.");
            }
        }
        else
        {
            throw new ArgumentException(
                $"No page with key: {pageKey}. Did you forget to call the Configure method?",
                nameof(pageKey));
        }
    }
    finally
    {
        _lock.Release();
    }
}
[Update:] Until the latest Xamarin.Forms release, there was no need to use the Device.BeginInvokeOnMainThreadmethod for the navigation itself. I only checked it recently that the Navigation needs now the call to it to dispatch the navigation to the main UI thread. Otherwise, the navigation will end in a dead thread on Android and iOS (but strangely not for UWP). I updated the code above and the source on Github as well.
I try to avoid passing parameters to pages while navigating, that’s why I added another task without the parameter overload as well:
Of course we will run into situations where we want to go back manually, for example in a cancel function. So we have a method for that as well:
public async Task GoBackAsync()
{
await _navigationPage.Navigation.PopAsync(true);
}
That’s  a lot of functionality already, but until now, we are only able to navigate to other pages and back. We want to support modal pages as well, so we’ll have some more methods to implement. They are following the same syntax as their navigation counterpart, so no surprise here:
public async Task ShowModalPageAsync(string pageKey, object parameter, bool animated = true)
{
    await _lock.WaitAsync();
Â
    try
    {
Â
        if (_pagesByKey.ContainsKey(pageKey))
        {
            var type = _pagesByKey[pageKey];
            ConstructorInfo constructor = null;
            object[] parameters = null;
Â
            if (parameter == null)
            {
                constructor = type.GetTypeInfo()
                    .DeclaredConstructors
                    .FirstOrDefault(c => !c.GetParameters().Any());
Â
                parameters = new object[]
                {
                };
            }
            else
            {
                constructor = type.GetTypeInfo()
                    .DeclaredConstructors
                    .FirstOrDefault(
                        c =>
                        {
                            return c.GetParameters().Count() == 1
                                   && c.GetParameters()[0].ParameterType == parameter.GetType();
                        });
Â
                parameters = new[] { parameter };
            }
Â
Â
            var page = constructor.Invoke(parameters) as Page;
Â
            if (_navigationPage != null)
            {
                Device.BeginInvokeOnMainThread(async () =>
                {
                    await _navigationPage.Navigation.PushModalAsync(page, animated);
                });
            }
            else
            {
                throw new NullReferenceException("there is no navigation page present, please check your page architecture and make sure you have called the Initialize Method before.");
            }
        }
        else
        {
            throw new ArgumentException($"No page found with key: {pageKey}. Did you forget to call the Configure method?", nameof(pageKey));
        }
    }
    finally
    {
        _lock.Release();
    }
}
public async Task GoBackModalAsync()
{
await _navigationPage.Navigation.PopModalAsync(true);
}
The last things that I wanted to note are properties that return the current counts of both the modal and the navigation stack of the navigation page as well as the GoHomeAsync() method to return to the root page. You will see these in the source code on Github.
IViewEventBrokerService implementation
Like I wrote already before, sometimes we need to know when a view is appearing/disappearing. In that case, the IViewEventBrokerService comes in. The implementation is pretty straight forward:
public class ViewEventBrokerService : IViewEventBrokerService
{
public event EventHandler<ViewEventBrokerEventArgs> ViewAppearing;
public event EventHandler<ViewEventBrokerEventArgs> ViewDisAppearing;
public void RaiseViewAppearing(string pageKey, Type pageType, bool isModal)
{
ViewAppearing?.Invoke(this, new ViewEventBrokerEventArgs(pageKey, pageType, isModal));
}
public void RaiseViewDisAppearing(string pageKey, Type pageType, bool isModal)
{
ViewDisAppearing?.Invoke(this, new ViewEventBrokerEventArgs(pageKey, pageType, isModal));
}
}
We have two events that can be raised with their corresponding Raise… methods. That’s all we have to do in here.
Implementing the Interfaces in Views (Pages)
Well, we have written a lot of code until here, now it is time to actually use it. As I want all my pages to be raise their appearing and disappearing automatically, I created a new base class, derived from Xamarin.Forms’Â ContentPage:
public class XfNavContentPage : ContentPage
{
private IViewEventBrokerService _viewEventBroker;
private IXfNavigationService _navService;
public XfNavContentPage()
{
_viewEventBroker = SimpleIoc.Default.GetInstance<IViewEventBrokerService>();
_navService = SimpleIoc.Default.GetInstance<IXfNavigationService>();
}
public static BindableProperty RegisteredPageKeyProperty = BindableProperty.Create("RegisteredPageKey", typeof(string), typeof(XfNavContentPage), default(string), BindingMode.Default, propertyChanged: OnRegisteredPageKeyChanged);
private static void OnRegisteredPageKeyChanged(BindableObject bindable, object oldValue, object newValue)
{
//todo, but not needed atm.
}
public string RegisteredPageKey
{
get { return (string)GetValue(RegisteredPageKeyProperty); }
set { SetValue(RegisteredPageKeyProperty, value); }
}
private(bool isRegistered, bool isModal) _stackState { get; private set; }
protected override void OnAppearing()
{
base.OnAppearing();
if (!string.IsNullOrEmpty(RegisteredPageKey))
{
_stackState = _navService.StackContainsNavKey(RegisteredPageKey);
if (_stackState.isRegistered)
{
_viewEventBroker?.RaiseViewAppearing(RegisteredPageKey, GetType(), _stackState.isModal);
}
}
}
protected override void OnDisappearing()
{
base.OnDisappearing();
if (!string.IsNullOrEmpty(RegisteredPageKey))
{
if (_stackState.isRegistered)
{
_viewEventBroker?.RaiseViewDisAppearing(RegisteredPageKey, GetType(), _stackState.isModal);
}
}
}
}
Let me explain what this base class does. It provides a BindableProperty(which is the Xamarin.Forms version of a DependencyProperty) that takes the registered key to provide it as a parameter. You can bind the key from your ViewModel or set it in code behind/XAML directly, all these ways will work. The base page implements our interfaces of the IXfNavigationService and the IViewBrokerServiceinterfaces as members and loads them in its constructor. The _stackStatemember is just an easy way to provide the needed data to the event-raising methods of our IViewEventBrokerservice. If used correctly, every page that derives from this base class will throw the corresponding events, which can be used in other parts of our application then.
Implementing the Interfaces in ViewModels
Like I did for Views, I am also creating a new base class for ViewModels that implement our two interfaces. Here is how it looks like:
public class XfNavViewModelBase : ViewModelBase
{
protected readonly IXfNavigationService _navService;
protected readonly IViewEventBrokerService _viewEventBroker;
public XfNavViewModelBase()
{
_navService = SimpleIoc.Default.GetInstance<IXfNavigationService>();
_viewEventBroker = SimpleIoc.Default.GetInstance<IViewEventBrokerService>();
_viewEventBroker.ViewAppearing += OnCorrespondingViewAppearing;
_viewEventBroker.ViewDisAppearing += OnCorrespondingViewDisappearing;
}
protected virtual void OnCorrespondingViewAppearing(object sender, ViewEventBrokerEventArgs e)
{
}
protected virtual void OnCorrespondingViewDisappearing(object sender, ViewEventBrokerEventArgs e)
{
}
private string _correspondingViewKey;
public string CorrespondingViewKey
{
get => _correspondingViewKey; set => Set(ref _correspondingViewKey, value);
}
public bool IsBoundToModalView()
{
if (!string.IsNullOrEmpty(CorrespondingViewKey))
{
var checkIfIsModal = _navService.StackContainsNavKey(CorrespondingViewKey);
if (checkIfIsModal.isRegistered)
{
return checkIfIsModal.isModal;
}
}
return false;
}
}
The XfNavViewModelBase implements both the IXfNavigationService and the IViewEventBrokerService interfaces. It also registers for the events thrown by IViewEventBrokerService. Making them virtual allows us to override them in derived ViewModels, if we need to. It has a string property to set the name of the View we want to use it in as well as a method that checks automatically if we are on a modal page if it gets called.
Using the created navigation setup
Now our navigation setup is ready it is time to have a look into how to use it. First we are going to create two pages, one for being shown modal, and one for being navigated to.
Then we’ll need to register and configure our services and pages in the ViewModelLocator. Remember the static RegisterServices() method we created in the first post? This is were we will throw the interface registrations in:
private static void RegisterServices()
{
    //this one gets the correct service implementation from platform implementation
    var osService = DependencyService.Get<IOsVersionService>();
Â
    // which can be used to register the service class with MVVMLight's Ioc
    SimpleIoc.Default.Register<IOsVersionService>(() => osService);
Â
    SimpleIoc.Default.Register<IXfNavigationService>(GetPageInstances);
    SimpleIoc.Default.Register<IViewEventBrokerService, ViewEventBrokerService>();
}
The method contains already our IOsVersionService from my last blog post. We are also using DI here for the IXfNavigationService, as we need to Configure our page keys as well. First, we are adding static strings as page keys to the ViewModelLocator:
public static string ModalPageKey => nameof(ModalPage);
public static string NavigatedPageKey => nameof(NavigatedPage);
I am always using the nameof()-operator for this, because it makes life a bit easier. The second step is the missing piece in the service registration, the GetPageInstances() method that returns an instance of the IXfNavigationService interface implentation and registers our two pages via the Configure() method.
public static XfNavigationService GetPageInstances()
{
var nav = new XfNavigationService();
nav.Configure(ModalPageKey, typeof(ModalPage));
nav.Configure(NavigatedPageKey, typeof(NavigatedPage));
return nav;
}
This all will never work if we are not using a NavigationPage. So we are going to load MainPage.xaml as a NavigationPagein App.xaml.cs and pass the navigation page to our IXfNavigationService:
public App()
{
InitializeComponent();
var rootNavigation = new NavigationPage(new View.MainPage());
MainPage = rootNavigation;
SimpleIoc.Default.GetInstance<IXfNavigationService>().Initialize(rootNavigation);
}
Modifying pages
Until now, the pages we created are standard ContentPages, so we need to make them derive from our earlier created base class. First we are adding the namespace of our base class to it:
After that, we are able to use the base class to change ContentPage to baseCtrl:XfNavContentPage. Now open the code behind file for the page and change it to derive from XfNavContentPage as well:
public partial class ModalPage : XfNavContentPage
The sample project has a modal page and a navigated page to demonstrate both ways.
Setting up ViewModels
Normally, we also have a ViewModel for every additional page. That´s why I created a ModalPageViewModel as well as a NavigatedPageViewModel for the sample. They derive from the XfNavViewModelBase, so wie can easyily hook up the view events (if needed):
public class ModalPageViewModel : XfNavViewModelBase
{
    public ModalPageViewModel()
    {
        CorrespondingViewKey = ViewModelLocator.ModalPageKey;
    }
    protected override void OnCorrespondingViewAppearing(object sender, ViewEventBrokerEventArgs e)
    {
        base.OnCorrespondingViewAppearing(sender, e);
    }
    protected override void OnCorrespondingViewDisappearing(object sender, ViewEventBrokerEventArgs e)
    {
        base.OnCorrespondingViewDisappearing(sender, e);
    }
    private RelayCommand _goBackCommand;
    public RelayCommand GoBackCommand => _goBackCommand ?? (_goBackCommand = new RelayCommand(async () =>
    {
        await _navService.GoBackModalAsync();
    }));
}
Remember the page keys we added earlier to the ViewModelLocator? We are just setting it as CorrespondingViewKey in the constructor here, but you could choose to it the way you prefer as well and can easily be bound to the view now:
As the sample pages have a button with back function, we have also a GoBackCommand bound to it. Now that’s already all we need to, and if we set a breakpoint in the event handling overrides, it will be hit as soon as the view is about to appear. See the sample working here in action on Android:
No we have a fully working and MVVM compliant navigation solution in Xamarin.Forms using the MVVMLight Toolkit.  I know there are several other toolkits and helpers floating around, but I like it to have less dependencies.  Another advantage of going this route: I am mostly familiar with the setup as I am already used to it from my Windows and Windows Phone applications. Creating this setup for navigation does not take a whole lot of time (the initial setup took me around 3 hours including conception). One can also pack the interfaces and the implementations in a (portable) class library to have all this work only once.
If you have feedback for me, feel free to leave a comment below. Like always, I hope this article is helpful for some of you. The updated sample application can be found here on my Github account.