Xamarin.Tip – Borderless Editor

I previously put out a post on removing the border of a Xamarin.Forms Entry which was then used to create a custom PinView as well as a MaterialEntry that follows the material design standards for text fields. Check those out here:

In this post, we’ll apply some of the same principles to create a BorderlessEditor. It’s going to use a simple custom renderer, although this could and should be done using an Effect if being used on its own. However, this BorderlessEditor will be the foundation for future controls.

You can find this code as part of my library in progress to create Material Design Form controls for Xamarin.Forms – https://github.com/SuavePirate/SuaveControls.MaterialFormControls.

Let’s get started with our custom control by first creating a custom subclass of Xamarin.Forms.Editor followed by a custom renderer class for iOS, Android, and UWP that kills the border.

BorderlessEditor.cs

namespace SuaveControls.MaterialForms
{
    public class BorderlessEditor : Editor
    {
    }
}

Nothing special here since we are using the default behavior of the Editor.

Android

Now let’s create an Android custom renderer.

BorderlessEditorRenderer.cs – Android

[assembly: ExportRenderer(typeof(BorderlessEditor), typeof(BorderlessEditorRenderer))]
namespace SuaveControls.MaterialForms.Android.Renderers
{
    public class BorderlessEditorRenderer : EditorRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
        {
            base.OnElementChanged(e);
            if (e.OldElement == null)
            {
                Control.Background = null;

                var layoutParams = new MarginLayoutParams(Control.LayoutParameters);
                layoutParams.SetMargins(0, 0, 0, 0);
                LayoutParameters = layoutParams;
                Control.LayoutParameters = layoutParams;
                Control.SetPadding(0, 0, 0, 0);
                SetPadding(0, 0, 0, 0);
            }
        }
    }
}

We simple kill the default padding and margins while setting the Background property to null. This Background is what creates the drawable underline for the AppCompat Editor.

iOS

Follow with an iOS renderer.

BorderlessEditorRenderer.cs – iOS

[assembly: ExportRenderer(typeof(BorderlessEditor), typeof(BorderlessEditorRenderer))]
namespace SuaveControls.MaterialForms.iOS.Renderers
{
    public class BorderlessEditorRenderer : EditorRenderer
    {
        public static void Init() { }
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            Control.Layer.BorderWidth = 0;
        }
    }
}

All we do here is set the BorderWidth to 0.

UWP

Lastly a renderer for UWP

BorderlessEditorRenderer.cs – UWP


[assembly: ExportRenderer(typeof(BorderlessEditor), typeof(BorderlessEditorRenderer))]

namespace SuaveControls.MaterialForms.UWP.Renderers
{
    public class BorderlessEditorRenderer : EditorRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                Control.BorderThickness = new Windows.UI.Xaml.Thickness(0);
                Control.Margin = new Windows.UI.Xaml.Thickness(0);
                Control.Padding = new Windows.UI.Xaml.Thickness(0);
            }
        }
    }
}

Similar to how we did it on Android, we set both the Margin and Padding to 0 and also set the BorderThickness to a 0’d Thickness.

Using the BorderlessEditor

Now you can use the BorderlessEditor in your XAML or C# code:

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ExampleMaterialApp"
             xmlns:suave="clr-namespace:SuaveControls.MaterialForms;assembly=SuaveControls.MaterialForms"
             x:Class="ExampleMaterialApp.MainPage">

    <ScrollView>
        <StackLayout Spacing="16" Margin="16" BackgroundColor="Blue">
            <Label Text="Borderless Editor!" Margin="32" HorizontalOptions="Center" HorizontalTextAlignment="Center"/>
            <suave:BorderlessEditor BackgroundColor="Black" TextColor="White" HeightRequest="300" Margin="32"/>

        </StackLayout>
    </ScrollView>

</ContentPage>

Check out those results on iOS:

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Advertisements

Xamarin.Tip – Borderless TimePicker

I previously put out a post on removing the border of a Xamarin.Forms Entry which was then used to create a custom PinView as well as a MaterialEntry that follows the material design standards for text fields. I also added a post just like this one that talks about creating a BorderlessPicker. Check those out here:

In this post, we’ll do exactly what we did with the BorderlessPicker, but apply it to the Xamarin.Forms.TimePicker control to remove the border. This would ideally be done using an Effect, however we will be using this control in a later post to create a MaterialTimePicker to fit the Material Design standards for form inputs, so we will create custom renderers for Android, iOS, and UWP.

You can find this code as part of my library in progress to create Material Design Form controls for Xamarin.Forms – https://github.com/SuavePirate/SuaveControls.MaterialFormControls.

Let’s get started with our custom control by first creating a custom subclass of Xamarin.Forms.TimePicker followed by a custom renderer class for iOS, Android, and UWP that kills the border.

BorderlessTimePicker.cs

namespace SuaveControls.MaterialForms
{
    public class BorderlessTimePicker : TimePicker
    {
    }
}

Nothing special here since we are using the default behavior of the TimePicker.

Android

Now let’s create an Android custom renderer.

BorderlessTimePickerRenderer.cs – Android

[assembly: ExportRenderer(typeof(BorderlessTimePicker), typeof(BorderlessTimePickerRenderer))]
namespace SuaveControls.MaterialForms.Android.Renderers
{
    public class BorderlessTimePickerRenderer : TimePickerRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
        {
            base.OnElementChanged(e);
            if (e.OldElement == null)
            {
                Control.Background = null;

                var layoutParams = new MarginLayoutParams(Control.LayoutParameters);
                layoutParams.SetMargins(0, 0, 0, 0);
                LayoutParameters = layoutParams;
                Control.LayoutParameters = layoutParams;
                Control.SetPadding(0, 0, 0, 0);
                SetPadding(0, 0, 0, 0);
            }
        }
    }
}

We simple kill the default padding and margins while setting the Background property to null. This Background is what creates the drawable underline for the AppCompat TimePicker.

iOS

Follow with an iOS renderer.

BorderlessTimePickerRenderer.cs – iOS

[assembly: ExportRenderer(typeof(BorderlessTimePicker), typeof(BorderlessTimePickerRenderer))]
namespace SuaveControls.MaterialForms.iOS.Renderers
{
    public class BorderlessTimePickerRenderer : TimePickerRenderer
    {
        public static void Init() { }
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            Control.Layer.BorderWidth = 0;
            Control.BorderStyle = UITextBorderStyle.None;
        }
    }
}

All we do here is set the BorderWidth to 0 and the BorderStyle to UITextBorderStyle.None.

UWP

Lastly a renderer for UWP

BorderlessTimePickerRenderer.cs – UWP


[assembly: ExportRenderer(typeof(BorderlessTimePicker), typeof(BorderlessTimePickerRenderer))]

namespace SuaveControls.MaterialForms.UWP.Renderers
{
    public class BorderlessTimePickerRenderer : TimePickerRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                Control.BorderThickness = new Windows.UI.Xaml.Thickness(0);
                Control.Margin = new Windows.UI.Xaml.Thickness(0);
                Control.Padding = new Windows.UI.Xaml.Thickness(0);
            }
        }
    }
}

Similar to how we did it on Android, we set both the Margin and Padding to 0 and also set the BorderThickness to a 0’d Thickness.

Using the BorderlessTimePicker

Now you can use the BorderlessTimePicker in your XAML or C# code:

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ExampleMaterialApp"
             xmlns:suave="clr-namespace:SuaveControls.MaterialForms;assembly=SuaveControls.MaterialForms"
             x:Class="ExampleMaterialApp.MainPage">

    <ScrollView>
        <StackLayout Spacing="16" Margin="16">
            <Label Text="Borderless TimePicker!" Margin="32" HorizontalOptions="Center" HorizontalTextAlignment="Center"/>
            <suave:BorderlessTimePicker/>

        </StackLayout>
    </ScrollView>

</ContentPage>

Check out those results on iOS:

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Xamarin.Tip – Borderless DatePicker

I previously put out a post on removing the border of a Xamarin.Forms Entry which was then used to create a custom PinView as well as a MaterialEntry that follows the material design standards for text fields. I also added a post just like this one that talks about creating a BorderlessPicker. Check those out here:

In this post, we’ll do exactly what we did with the BorderlessPicker, but apply it to the Xamarin.Forms.DatePicker control to remove the border. This would ideally be done using an Effect, however we will be using this control in a later post to create a MaterialDatePicker to fit the Material Design standards for form inputs, so we will create custom renderers for Android, iOS, and UWP.

You can find this code as part of my library in progress to create Material Design Form controls for Xamarin.Forms – https://github.com/SuavePirate/SuaveControls.MaterialFormControls.

Let’s get started with our custom control by first creating a custom subclass of Xamarin.Forms.DatePicker followed by a custom renderer class for iOS, Android, and UWP that kills the border.

BorderlessDatePicker.cs

namespace SuaveControls.MaterialForms
{
    public class BorderlessDatePicker : DatePicker
    {
    }
}

Nothing special here since we are using the default behavior of the DatePicker.

Android

Now let’s create an Android custom renderer.

BorderlessDatePickerRenderer.cs – Android

[assembly: ExportRenderer(typeof(BorderlessDatePicker), typeof(BorderlessDatePickerRenderer))]
namespace SuaveControls.MaterialForms.Android.Renderers
{
    public class BorderlessDatePickerRenderer : DatePickerRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
        {
            base.OnElementChanged(e);
            if (e.OldElement == null)
            {
                Control.Background = null;

                var layoutParams = new MarginLayoutParams(Control.LayoutParameters);
                layoutParams.SetMargins(0, 0, 0, 0);
                LayoutParameters = layoutParams;
                Control.LayoutParameters = layoutParams;
                Control.SetPadding(0, 0, 0, 0);
                SetPadding(0, 0, 0, 0);
            }
        }
    }
}

We simple kill the default padding and margins while setting the Background property to null. This Background is what creates the drawable underline for the AppCompat DatePicker.

iOS

Follow with an iOS renderer.

BorderlessDatePickerRenderer.cs – iOS

[assembly: ExportRenderer(typeof(BorderlessDatePicker), typeof(BorderlessDatePickerRenderer))]
namespace SuaveControls.MaterialForms.iOS.Renderers
{
    public class BorderlessDatePickerRenderer : DatePickerRenderer
    {
        public static void Init() { }
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            Control.Layer.BorderWidth = 0;
            Control.BorderStyle = UITextBorderStyle.None;
        }
    }
}

All we do here is set the BorderWidth to 0 and the BorderStyle to UITextBorderStyle.None.

UWP

Lastly a renderer for UWP

BorderlessDatePickerRenderer.cs – UWP


[assembly: ExportRenderer(typeof(BorderlessDatePicker), typeof(BorderlessDatePickerRenderer))]

namespace SuaveControls.MaterialForms.UWP.Renderers
{
    public class BorderlessDatePickerRenderer : DatePickerRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                Control.BorderThickness = new Windows.UI.Xaml.Thickness(0);
                Control.Margin = new Windows.UI.Xaml.Thickness(0);
                Control.Padding = new Windows.UI.Xaml.Thickness(0);
            }
        }
    }
}

Similar to how we did it on Android, we set both the Margin and Padding to 0 and also set the BorderThickness to a 0’d Thickness.

Using the BorderlessDatePicker

Now you can use the BorderlessDatePicker in your XAML or C# code:

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ExampleMaterialApp"
             xmlns:suave="clr-namespace:SuaveControls.MaterialForms;assembly=SuaveControls.MaterialForms"
             x:Class="ExampleMaterialApp.MainPage">

    <ScrollView>
        <StackLayout Spacing="16" Margin="16">
            <Label Text="Borderless DatePicker!" Margin="32" HorizontalOptions="Center" HorizontalTextAlignment="Center"/>
            <suave:BorderlessDatePicker/>

        </StackLayout>
    </ScrollView>

</ContentPage>

Check out those results on iOS:

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Xamarin.Tip – Borderless Picker

I previously put out a post on removing the border of a Xamarin.Forms Entry which was then used to create a custom PinView as well as a MaterialEntry that follows the material design standards for text fields. Check those out here:

In this post, we’ll apply some of the same principles to create a BorderlessPicker. It’s going to use a simple custom renderer, although this could and should be done using an Effect if being used on its own. However, this BorderlessPicker will be the foundation for future controls we will create such as the MaterialPicker that applies Material Design standards to the Xamarin.Forms Picker control on Android, iOS, and UWP.

You can find this code as part of my library in progress to create Material Design Form controls for Xamarin.Forms – https://github.com/SuavePirate/SuaveControls.MaterialFormControls.

Let’s get started with our custom control by first creating a custom subclass of Xamarin.Forms.Picker followed by a custom renderer class for iOS, Android, and UWP that kills the border.

BorderlessPicker.cs

namespace SuaveControls.MaterialForms
{
    public class BorderlessPicker : Picker
    {
    }
}

Nothing special here since we are using the default behavior of the Picker.

Android

Now let’s create an Android custom renderer.

BorderlessPickerRenderer.cs – Android

[assembly: ExportRenderer(typeof(BorderlessPicker), typeof(BorderlessPickerRenderer))]
namespace SuaveControls.MaterialForms.Android.Renderers
{
    public class BorderlessPickerRenderer : PickerRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
        {
            base.OnElementChanged(e);
            if (e.OldElement == null)
            {
                Control.Background = null;

                var layoutParams = new MarginLayoutParams(Control.LayoutParameters);
                layoutParams.SetMargins(0, 0, 0, 0);
                LayoutParameters = layoutParams;
                Control.LayoutParameters = layoutParams;
                Control.SetPadding(0, 0, 0, 0);
                SetPadding(0, 0, 0, 0);
            }
        }
    }
}

We simple kill the default padding and margins while setting the Background property to null. This Background is what creates the drawable underline for the AppCompat Picker.

iOS

Follow with an iOS renderer.

BorderlessPickerRenderer.cs – iOS

[assembly: ExportRenderer(typeof(BorderlessPicker), typeof(BorderlessPickerRenderer))]
namespace SuaveControls.MaterialForms.iOS.Renderers
{
    public class BorderlessPickerRenderer : PickerRenderer
    {
        public static void Init() { }
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            Control.Layer.BorderWidth = 0;
            Control.BorderStyle = UITextBorderStyle.None;
        }
    }
}

All we do here is set the BorderWidth to 0 and the BorderStyle to UITextBorderStyle.None.

UWP

Lastly a renderer for UWP

BorderlessPickerRenderer.cs – UWP


[assembly: ExportRenderer(typeof(BorderlessPicker), typeof(BorderlessPickerRenderer))]

namespace SuaveControls.MaterialForms.UWP.Renderers
{
    public class BorderlessPickerRenderer : PickerRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                Control.BorderThickness = new Windows.UI.Xaml.Thickness(0);
                Control.Margin = new Windows.UI.Xaml.Thickness(0);
                Control.Padding = new Windows.UI.Xaml.Thickness(0);
            }
        }
    }
}

Similar to how we did it on Android, we set both the Margin and Padding to 0 and also set the BorderThickness to a 0’d Thickness.

Using the BorderlessPicker

Now you can use the BorderlessPicker in your XAML or C# code:

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ExampleMaterialApp"
             xmlns:suave="clr-namespace:SuaveControls.MaterialForms;assembly=SuaveControls.MaterialForms"
             x:Class="ExampleMaterialApp.MainPage">

    <ScrollView>
        <StackLayout Spacing="16" Margin="16">
            <Label Text="Borderless Picker!" Margin="32" HorizontalOptions="Center" HorizontalTextAlignment="Center"/>
            <suave:BorderlessPicker x:Name="PickerDemo" Title="Options"/>

        </StackLayout>
    </ScrollView>

</ContentPage>

MainPage.xaml.cs

    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

            PickerDemo.ItemsSource = new List<string>
            {
                "Option 1",
                "Option 2",
                "Option 3",
                "Option 4"
            };
        }
    }

Check out those results on iOS:

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Xamarin.Controls – MarkdownTextView

Markdown is cool, and we as developers are seeing more and more of it all around us; documentation, chat, or even just trying to store dynamic displayed strings without storing the crazy extra characters of xml or html.

Markdown is used by parsing it through a series of Regex comparisons and outputting the html equivalent of what is to be displayed. In web, that’s awesome! Parse the markdown, dump it in the DOM. Bam.

But what about native mobile development? I’ve seen solutions out there where people just create a WebView on their platform, and dump the parsed html from the markdown string into that WebView. It might get the job done in a simple scenario, but WebViews are hefty and really should be avoided.

I’ve created a free and open sourced solution to this problem – The MarkdownTextView.

Here’s the repo: https://github.com/SuavePirate/MarkdownTextView

This is a Xamarin.Forms control that renders on iOS and Android. It consumes a string through the Markdown property, and then the custom render on the respective platform renders it out via a UILabel on iOS and a TextView on Android.

Using the MarkdownTextView

To use the control, clone the repository and reference the library projects in your application. Reference the PCL in your PCL or Shared Library, and reference the native library with the renderer in your platform specific project.

In your platform projects, be sure to call:


MarkdownTextView.Init();

Then use the control in either your XAML or your C# page/view:


<ContentPage ...
xmlns:spcontrols="clr-namespace:SPControls.Forms;assembly=SPControls.MarkdownTextView"
...>
<spcontrols:MarkdownTextView Markdown="{Binding MarkdownString}" />
</ContentPage>

var mdTextView = new MarkdownTextView();
mdTextView.Markdown = "# this is my *header* tag";

How It Works

There are five core steps to how the control works:

  1. The Xamarin.Forms control takes the string value from the Markdown property
  2. The Native custom renderer gets the updated string
  3. The native control calls the PCL Markdown class to parse the string into an html string (with some extra clean up)
  4. The native library parses the html string into a platform specific attributed string that the control can render.
    1. iOS: NSAttributedString
    2. Android: ICharSequence
  5. The native renderer then renders the value from the above type into the native control.
    1. iOS: UILabel.AttributedText
    2. Android: TextView.TextFormatted

There are a few smaller steps specific to the platform to handle some tags that are not normally built in, but that’s the basics.

In a follow-up blog post, I will talk about the details of how this is accomplished for each platform, and how to take this outside Xamarin.Forms to use in your native Xamarin applications.

Xamarin.Tips – Extending Xamarin Plugins

An Introduction to Plugins

If you’re on my blog, you know I love Xamarin. Writing cross-platform applications and sharing as much code as possible is, in my opinion, the way to go. The Xamarin community has taken an awesome technology, and made it even more awesome by building tons and tons of plugins. These plugins allow us to access platform-specific functionality from shared code, which simply allows us as application developers to write even more code in our portable projects.

I ran into an interesting forum post talking about the structure of plugins made a standard by Xamarin. A lot of use these plugins, but of course, they are not made for everyone! I’ve seen many repositories riddled with issues asking for more and more features in the plugin. This post is going to show some ways to expand on those features with your own code! As well as show techniques to use these plugins with Inversion of Control and Dependency Injection, rather than through the Singleton that the standard ships with.

Suggested Resources Before Starting

It might be a good idea to read up on my blogs and watch my videos about calling platform specific code from a PCL. Check out the YouTube playlist for some different techniques. Specifically looking at the Singleton method and Dependency Injection method.

Resources for Examples

We are going to look at arguably my all time favorite plugin: UserDialogs by Allan Ritchie

If you haven’t used it yet, it’s a cool plugin that allows you to call platform specific pop ups and dialogs including alerts, toasts, prompts, action sheets, confirmation messages, and more.

We are also going to be using MvvmLight (as I tend to do) in order to use SimpleIoc for our Inversion of Control and Dependency Injection.

Let’s first look at using IoC and DI, then look at extending the functionality.

Use Dependency Injection to Call Your Plugins

If we look at Singleton of UserDialogs, we see that it simply changes the Init method based on the platform, and uses that to set the platform-specific implementation of IUserDialogs. The core of the functionality comes from that implementation of IUserDialogs. So rather than going through the Init method of the Singleton, we can instead register the implementation to an IoC container, and inject it into the constructor of our ViewModel or Service that calls it!

Let’s create a ViewModel that takes an IUserDialogs in its constructor:

public class MyViewModel : ViewModelBase
{
    ...
    private readonly IUserDialogs _userDialogs;
    public MyViewModel(IUserDialogs userDialogs)
    {
        _userDialogs = userDialogs;
    }
    ...
 }

Now that our ViewModel has a reference to an IUserDialogs, we can make calls to it from ICommands or methods.

public void ErrorToast(string message)
{
    // show a toast message with a red background
    _userDialogs.Toast(new ToastConfig(message).SetMessageTextColor(System.Drawing.Color.White).SetBackgroundColor(System.Drawing.Color.FromArgb(255, 213, 0, 0)));
}

 

 

Now all we need to do is register both our IUserDialogs platform implementation and our MyViewModelto our IoC container.

In our PCL or SharedLibrary:


...
ServiceLocator.SetLocatorProvider(() =&gt; SimpleIoc.Default);
...
SimpleIoc.Default.Register&lt;MyViewModel&gt;();
...

Then in our Android project:


...

 ActivityLifecycleCallbacks.Register(activity);
var userDialogsImplementation = new UserDialogsImpl(() =&gt; ActivityLifecycleCallbacks.CurrentTopActivity);
SimpleIoc.Default.Register&lt;IUserDialogs&gt;(() =&gt; userDialogsImplementation);
...

And in iOS:

...
// note iOS doesn't require registering lifecycle callbacks like iOS does.
SimpleIoc.Default.Register&lt;IUserDialogs, UserDialogsImpl();
...

Now when we create our MyViewModel, we don’t do it through calling new MyViewModel(), we will call to get the instance from the ServiceLocator. For example, we can set the BindingContext of a Page:

 

...
public MyMainPage()
{
    BindingContext = ServiceLocator.Current.GetInstance&lt;MyViewModel&gt;();
}
...

That’s all we need to do! As long as we make those Register calls for our MyViewModel and IUserDialogs before the call to the MyMainPage constructor, everything will be wired up and Injected.

Now that we have our application using Dependency Injection instead of the Singleton, it makes it even easier to override and extend the functionality of the plugin.

Changing Features and Functionality

There are only two things we need to change to our implementation from above.

  1. Create a new platform implementation of IUserDialogs that inherits from the UserDialogsImpl.
  2. Change the IoC Registration to use our new implementation.

Let’s create a new class called MyUserDialogsImpl that will inherit from UserDialogsImpl. In this class, we will override the Alert method and do something like change the Tint color on iOS:


public class MyUserDialogsImpl : UserDialogsImpl
{
    ...
    public override IDisposable Alert(AlertConfig config)
    {
        return this.Present(() =&gt;
        {
             var alert = UIAlertController.Create(config.Title ?? String.Empty, config.Message, UIAlertControllerStyle.Alert);

            // custom piece:
            alert.View.TintColor = UIColor.Red;

             alert.AddAction(UIAlertAction.Create(config.OkText, UIAlertActionStyle.Default, x =&amp;amp;amp;amp;amp;gt; config.OnAction?.Invoke()));
             return alert;
         });
     }

 ...
}

Now where we registered the IUserDialogs before, we just substitute our new implementation!

 

...
// note iOS doesn't require registering lifecycle callbacks like iOS does.
SimpleIoc.Default.Register&lt;IUserDialogs, MyUserDialogsImpl&gt;();
...

So now our IoC set up will automatically set up our new implementation, so when we call the Alert method, it will show the Tint color as Red.

Adding New Features to Plugins

Similarly to how we changed functionality, we can add completely new functionality in just a few steps:

  1. Create a new Interface that inherits IUserDialogs in our shared code.
  2. Add a new method to that interface
  3. Change our new implementation to also implement that new interface
  4. Change our IoC Registration to register our implementation as our new interface instead of IUserDialogs
  5. Change our injected dependency in our MyViewModel to our new interface

In our shared code, let’s create an interface called ICustomDialogs and add a method to its definition:


public interface ICustomDialogs : IUserDialogs
{
    void SayHello();
}

 

Now, let’s update our MyUserDialogsImpl to implement our new interface:


public class MyUserDialogsImpl : UserDialogsImpl, ICustomDialogs
{
    public void SayHello()
    {
        this.Alert(&quot;Hello&quot;, &quot;World&quot;);
    }
}

Next, we need to update our IoC Register call:

 

 


...
SimpleIoc.Default.Register&lt;ICustomDialogs, MyUserDialogsImpl&gt;();
...

Lastly, let’s change our MyViewModel to use our new interface:

public class MyViewModel : ViewModelBase 
{ 
    ...
    private readonly ICustomDialogs _userDialogs; 
    public MyViewModel(ICustomDialogs userDialogs)
    {
        _userDialogs = userDialogs; 
    } 
    ...
}

Now we can call our SayHello method from our ViewModel too!

Recap

  1. Xamarin Plugins are awesome
  2. You don’t have to use Plugin Singletons!
  3. You can use dependency injection to inject your plugin implementations
  4. You can override methods in your platform specific implementations of your plugins
  5. You can create new functionality through another interface and updated injections!

Xamarin Component Review: ModernHttpClient

These reviews consist of a Pros/Cons, some things developers might need to be aware of before using or during the use of a given component, and a quick code sample that might help people get started.

Links:
Component https://components.xamarin.com/view/modernhttpclient
Nuget – https://www.nuget.org/packages/modernhttpclient/
Github – https://github.com/paulcbetts/ModernHttpClient

Pros:

  • Increase HTTP request speeds.
    This really does make a noticeable difference from using the base
    HttpWebRequest,HttpClient, or WebClient. By using native libraries, it can skip through the Mono runtime bottleneck.
  • Ease of Use.
    Probably the easiest to use component you’re going to find, especially if you are already using HttpClient for your requests. It’s a simple one line drop on each instantiation of HttpClient.
new HttpClient(new NativeMessageHandler());
  • Lightweight.
    A common issue with components is that they increase the overall size of your app. Bigger apps get uninstalled quicker if they don’t do anything important for the user.

Cons:

  • Component conflict.
    Most people won’t run into this issue, and it is most prevalent on Android (at least it is the only place I’ve run into it). The problem arises because of ModernHttpClient’s use of OkHttp from SquareThe way they include this library is different from some others that are dependent on it. You’ll find components such as Picasso or Rounded Image View that also use OkHttp handle it differently, so that at build time, you’ll get a very deceiving error message.

Things to know:

The only things that I have been made aware of so far in my use of ModernHttpClient are a few out of place errors or bugs I’ve run across. Note that these are only found on Android.
1. The component conflict issue (as stated above): You can see an example from a thread here on this type of issue.
2. Android “crash” while debugging. This is an issue apparent with OkHttp that seems to cause crashes while debugging an Android app, while still maintaining the debugger. It is important to note that this does NOT cause this type of crash if the debugger is not attached. Also, after a crash, upon re-opening the app, the debugger remains attached and usable. Something along the lines of

F/libc( 1044): Fatal signal 5 (SIGTRAP), code -6 in tid 1131 (OkHttp Dispatch)

I haven’t tried the pro version, since the free license does exactly what I need, but if anyone has any insight into the pro license, let me know.

Sample:

...
using ModernHttpClient;
...

public class WebRequestUtils
{
    public async Task<string> GetResponseString(url)
    {
// Instantiate HttpClient with ModernHttpClient handler
using(var client = new HttpClient(new NativeMessageHandler())
        {
            var result = await client.GetAsync(url);
            return await result.Content.ReadAsStringAsync();
        }
    }
}

Make sure to keep an eye out for more component reviews as I get around to playing with more in real life situations.