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.

Advertisements

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.