Images captured by iOS show up rotated on Android

When you capture a photo with TakePhotoAsync on the iOS, regardless of the SaveMetaData flag or RotateImage, it might be stored rotated. However, you won’t notice it on the iOS itself, or on Windows, since the orientation information is stored in the EXIF metadata of the captured JPEG file.

iOS or Windows show the image correctly because they take into account the EXIF orientation, but the Image view of Xamarin.Forms on Android ignores this flag, thus making the image show up as-is, i.e. rotated.

If you store the image in a different format than JPEG (e.g. PNG) on the iOS, you can also see the image rotated there, because PNG doesn’t have an orientation flag.

If you are using Xamarin.Forms, consider using CachedImage from FFImageLoading instead of the built-in Image view. CachedImage looks at the orientation information on Android, and rotates the image accordingly before rendering it.

However, if you are uploading the image to an ASP.NET core application and need to process it, you can rotate it manually based on the EXIF information. .NET core by itself doesn’t have image manipulation capabilities, but you can install the CoreCompat.System.Drawing NuGet package, which is a port of System.Drawing for .NET core.

First, load the image as an Image object:

var image = Image.FromFile(path);

Then see if it has the rotation value, and rotate accordingly:

if (image.PropertyIdList.Contains(0x112))
{
    int rotationValue = image.GetPropertyItem(0x112).Value[0];
    if (rotationValue == 8) 
        image.RotateFlip(rotateFlipType: RotateFlipType.Rotate270FlipNone);
    else if (rotationValue == 3) 
        image.RotateFlip(rotateFlipType: RotateFlipType.Rotate180FlipNone);
    else if (rotateValue == 6)
        image.RotateFlip(rotateFlipType: RotateFlipType.Rotate90FlipNone);
}

Optionally, you can save the image on the original file:

image.Save(path);

 

Preventing multiple clicks on Xamarin.Forms buttons

I encountered this issue many times where a button was supposed to open a modal page, and tapping on that button repeatedly would open the modal page several times.

To prevent this, you can create a simple custom renderer for the Button class, and put a timer which disables the button for a short period of time after each successful tap:

#if __ANDROID__
    using Xamarin.Forms.Platform.Android;
    using Android.Views;
#elif __IOS__
    using Xamarin.Forms.Platform.iOS;
    using UIKit;
#endif

using Xamarin.Forms;
using System.Threading.Tasks;
using Neat.Renderers;

[assembly: ExportRenderer(typeof(Button), typeof(BlockingButtonRenderer))]
namespace Neat.Renderers
{
    public class BlockingButtonRenderer : ButtonRenderer
    {
        bool _isPressed = false;
        
#if __ANDROID__
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
        {
            base.OnElementChanged(e);
            
            var control = Control as Android.Widget.Button;
            control?.SetOnClickListener(ButtonClickListener.Instance.Value);
        }
        
        public async void SendBlockingClicked()
        {
            if (_isPressed) return;
            _isPressed = true;
            ((IButtonController)Element).SendClicked();
            await Task.Delay(500);
            _isPressed = false;
        }
        
        class ButtonClickListener : Java.Lang.Object, IOnClickListener
        {
            public static readonly Lazy<ButtonClickListener> Instance =
                new Lazy<ButtonClickListener>(() =>
                    new ButtonClickListener());
                    
            public void OnClick(Android.Views.View view)
            {
                var renderer = view.Tag as ButtonRenderer;
                (renderer as BlockingButtonRenderer)?.SendBlockingClicked();
            }
        }
#elif __IOS__
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
        {
            base.OnElementChanged(e);
            
            var control = Control as UIButton;
            if (control != null)
            {
                control.TouchUpInside += async (sender, ev) =>
                {
                    if (_isPressed) return;
                    _isPressed = true;
                    var oldInteractionFlag = control.UserInteractionEnabled;
                    control.UserInteractionEnabled = false;
                    await Task.Delay(500);
                    control.UserInteractionEnabled = oldInteractionFlag;
                    _isPressed = false;
                };
            }
        }
#endif
    }
}

REST requests with Xamarin and RestSharp

RestSharp (available on NuGet) is a clean way to send HTTP requests and handle their response. As a portable package, you can use it in your Xamarin.iOS and Xamarin.Android applications. The following example, POSTs a serialized JSON body, created automatically from a C# class, to an endpoint located at https://myserver.com/api/messages/message. It also sends a token parameter inside the query string:

public class MessageDTO : DTO
{
    public string Sender { get; set; }
    public string Recipient { get; set; }
    public string Body { get; set; }
}
public static class PinHelper
{
    async void SendMessage(MessageDTO dto)
    {
        const string ApiPath = "https://myserver.com/api/";
        var client = new RestClient (ApiPath);
        var request = new RestRequest ("messages/message", Method.POST);
        request.AddQueryParameter ("token", Settings.Token);
        request.AddJsonBody (dto);

        try
        {
            var result = await client.ExecuteTaskAsync(request);
            Debug.WriteLine($"Result Status Code: {result.StatusCode} - {result.Content}");
        }
        catch (Exception e) {
            Debug.WriteLine ($"Error: {e.Message}");
        }
    }
}

On an ASP.NET WebApi controller with EntityFramework, this request can be received and stored using a function that looks like this:

[HttpPost][Route("message")]
public IHTTPActionResult AddMessage(string token, [FromBody] MessageDTO dto)
{
    Message message = new Message ();
    dto.Inject (message);
    db.Messages.Add (message);
    db.SaveChanges ();

    return Ok ();
}

Tips and Tricks on Using SQLite-Net with Xamarin.iOS

SQLite-Net is a nice library compatible with Xamarin that lets you create and use a SQLite database as the local data source of your application. It is ultra portable as it comes in only two C# files, one of which is for asynchronous operations. You can easily get it from NuGet and get started with it.

Creating a database (if not exists)

The first step in using SQLite-Net is creating a database, and its tables. This is automatically done by creating a SQLiteAsyncConnection and calling its CreateTableAsync<T> method, in which T is your model class. This method checks for the existence of a table with the same name as the model class, and creates it if it does not exist. For example, if we want to make a database named map.db containing a table based on the model class Pin, we can do the following:


var path = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.Personal), "map.db");
var connection = new SQLiteAsyncConnection(PATH, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.FullMutex, true);
await connection.CreateTableAsync<Pin>();

You can keep the connection variable in case you’d like to use the database in the future, but be careful from which thread you access it. Many of the issues with SQLite-net come from accessing the database from a wrong thread, and the error messages usually give no hint regarding this.

Model classes

SQLite-Net takes care of serializing and deserializing data between queries and .NET objects. A model class can look like this:


using System;

using SQLite;


namespace Mapp.Models

{
    


        public class Pin
 

        {

        
        [PrimaryKey, AutoIncrement]


                public int Id { get; set; }
        
        public int ServerId { get; set; }

        
        public string Name { get; set; }

        
        public string Description { get; set; }


                public double Latitude { get; set; }


                public double Longitude { get; set; }


        }
}

In this example, the Id field is an auto-incremented primary key for table Pin.

Injecting DTO values into a model object

You can use the neat reflection features of .NET to automatically inject values from a Data Transfer Object (DTO) that is a subset of your model fields. Here is a helper method that does this for you:


using System.Linq;

using System.Reflection;


namespace Mapp

{

    public class DTO

    {

        public void Inject(object destination)

        {

            var destFields = destination.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

            var myFields = this.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);


            foreach (var item in myFields)

            {

                var matchingFields = from x in destFields where x.Name == item.Name select x;

                if (matchingFields.Count() == 0) continue;

                matchingFields.First().SetValue(destination, item.GetValue(this));

            }

        }

    }

}

For example if you have the following DTO, you can inject its values into a Pin object using the Inject method:


public class PinDTO : DTO

{
    public int ServerId { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }

    public double Latitude { get; set; }

    public double Longitude { get; set; }
}

...

Pin pin = new Pin();
pinDto.Inject(pin);

Querying, inserting and updating records

You can use LINQ syntax to query the database and get a list of objects of the type of your model class. For example to find a pin with a certain ServerId and update it (or create it if it does not exist) you can write:


var query = connection.Table<Pin>().Where(x => x.Id == dto.ServerId).ToListAsync().Result;
var pin = Query.Count > 0 ? query[0] : new Pin { ServerId = dto.ServerId };
dto.Inject(pin);

if (pin.Id > 0)
{
    // Record exists. Update it.
    await connection.UpdateAsync(pin);
}
else
{
    // Record does not exist. Create it.
    await connection.InsertAsync(pin);
}

Again, you have to be careful from which thread you are accessing the database. To delete a record you can use the DeleteAsync method:


await connection.DeleteAsync(pin);

Accessing Vimeo and YouTube APIs with Xamarin.iOS

The Uptred Source library allows you to build C# based applications for iOS that use Vimeo and YouTube APIs. You can easily authorize a Vimeo or YouTube account, and afterwards query data from the server or even have resumable uploads. This post covers the basics of using Uptred Source to build an application that communicates with Vimeo Advanced API and YouTube API using Xamarin.iOS.
Continue reading