Getting Started with Xamarin.Forms and Effects

Previous posts in this sequence:
Getting Started with Xamarin.Forms and Multi-Targeting in Visual Studio
Getting Started with Xamarin.Forms and SDK Versions
Getting Started with Xamarin.Forms with MvvmCross
Getting Started with Xamarin.Forms and Authenticating with ADAL
Getting Started with Xamarin.Forms, Refactoring MvvmCross and Services

At some point in building a cross platform application using Xamarin.Forms you’ll need to build out some platform specific features. There are a couple of ways to do this, depending on what you want to achieve. One of those ways is to use an Effect. In this example we’re going to create an Effect that can be used to add a tooltip to any element. For the purposes of this exercise we’re going to assume that this only makes sense to add on UWP where the application can be used on a desktop where the user has a mouse and keyboard attached.

An Effect has two parts:

– A platform agnostic class which will contain any properties that the Effect needs to expose in XAML. This is the name of the element that will appear in XAML. In this case the class will be called TooltipEffect and inherits from RoutingEffect

– A platform specific class which provides the platform specific implementation. In this case this class will be called TooltipPlatformEffect and inherits from PlatformEffect. Note that as this is platform specific, it needs to reside in the platform specific folder

As an Effect is a UI component, it should be added to the UI project, which should now look something like:

image

A couple of things to note here:

– There are folders for Converters, Effects and Renderers – I’ve added these as they are common elements that you’ll be adding to your UI project

– I’ve moved MainPage into a folder called Pages

– In a lot of cases I’ll have another folder called Controls, which will contain any custom or user controls I build.

– The TooltipEffect class sits in the Effects folder (platform agnostic)

– The TooltipEffect.Platform file, which contains the TooltipPlatformEffect class, sits in the Uap platform specific folder

Now, let’s look at the implementation of the effect. First, we’ll start with the TooltipEffect:

public class TooltipEffect : RoutingEffect
{
     public TooltipEffect() : base(“StrataPark.TooltipEffect“)
     {
     }


    public string Tooltip { get; set; }
}

This class exposes a Tooltip string property which will be used to specify the tooltip text in XAML. In the call to the base constructor it passes in a unique identifier for the Effect. This is important to note because it needs to align with the identifier used by the platform specific implementation. Speaking of which, here’s the TooltipPlatformEffect:

[assembly: ResolutionGroupName(“StrataPark”)]
[assembly: ExportEffect(typeof(TooltipPlatformEffect), nameof(TooltipEffect))]


namespace StrataPark.UI.Effects
{
     [Preserve]
     public class TooltipPlatformEffect : PlatformEffect
     {
         protected override void OnAttached()
         {
             var view = Control ?? Container;


            var effect = Element.Effects.OfType<TooltipEffect>().FirstOrDefault();
             if (!string.IsNullOrWhiteSpace(effect?.Tooltip) && view != null)
             {
                 var toolTip = new ToolTip
                 {
                     Content = effect?.Tooltip
                 };
                 ToolTipService.SetToolTip(view, toolTip);
             }
         }


        protected override void OnDetached()
         {
         }
     }
}

The most important part of this code are the assembly level attributes that register both the namespace (i.e. the StrataPark prefix) and the element identifier (nameof(TooltipEffect) gives the second part of the identifier, “ToolTipEffect”). If the combination of these attributes don’t yield the same identifier set in the platform agnostic Effect, the platform specific implementation won’t be loaded at runtime.

You can now use this Effect in XAML as follows

<Button Text=”Authenticate” Command=”{Binding AuthenticateCommand}”>
     <Button.Effects>
         <effects:TooltipEffect Tooltip=”Welcome tooltip”/>
    </Button.Effects>
</Button>

One last note – when adding folders to your project, you should keep an eye on the changes that take place in your csproj. When you add/remove files and folders, occasionally Visual Studio will add unnecessary items to the csproj. Remember that by default files and folders will be include in the new csproj format. So for example, the following xml is not required, and should be removed, prior to checking your code in:

<ItemGroup>
   <Folder Include=”Converters” />
   <Folder Include=”Renderers” />
</ItemGroup>

As you’ve seen, Effects are one way to add platform specific UI logic to your application. An alternative, is to use Renderers but that’s a topic for another post.

2 thoughts on “Getting Started with Xamarin.Forms and Effects”

  1. Please, don’t forget to add the namespaces when you show code if you want people to use it.
    And if you let me give a 2 cent advice, either give a basic implementation for iOS & Android or specify Xamarin Forms UWP instead of Xamarin Forms. I bet that more than 90% of xamarin forms projects target iOS and Android only.
    Some screenshots would be much appreciated too. I know it takes more times but if you found the time to write this post, you can spend 2 more minutes to make it worth it.

    ToolTip & ToolTipService are Windows specific.

    And last but not least, it’s weird to have the platform specific implementation in the core / shared project which is used as a reference by the iOS, Android and UWP projects.

    You can take a look at this post about Tooltip for Xamarin Forms to see a good exemple of what I was looking for : https://www.xamboy.com/2019/03/01/showing-tooltips-in-xamarin-forms/

    Reply
    • Hi,
      Thanks for dropping past
      I’m sorry if you weren’t able to take the example and apply it to iOS/Android.
      Yeh I could add screenshots but then I’d spend more time capturing images and less time writing useful content – it’s a balance, and in this case I didn’t see the need to provide a screenshot, since it was mostly focused on the code.
      Lastly, the project isn’t a shared project, it’s a multi-targeted project. And for this reason it’s 100% the correct way to do this.

      Reply

Leave a comment