Annoncing the Behaviors Toolkit for Xamarin!

February 2nd, 2016 | Posted by Tom in .NET | Xamarin - (0 Comments) | Read: 589

Since some days, I’ve started to work on a new project that, I hope, will help any Xamarin developers to improve their productivity.

Indeed, I’m very happy to announce that since today, the Behaviors Toolkit for Xamarin is now available !

image

What is it?

Currently in version 0.0.1, and as explained on the Github page, the Behaviors Toolkit for Xamarin is an easy-to-use means of adding common and reusable interactivity to your Xamarin applications with minimal code.

Why I’ve started to work on it?

Because I’m a lazy developer (or, at least, I’m a developer that like to reuse code) :)

Since I’ve been working on XAML applications, I’ve always enjoyed the behaviors feature which allow me to easily reuse the same feature on different controls. I’ve always thought it could be a good idea to get this in Xamarin apps because regardless the technology used: the needs are (often) the same.

Where to get it?

The source and documentation/code samples can be found in the Github repository:

https://github.com/ThomasLebrun/XamarinBehaviorsToolkit

If you want to access the package directly, you can get it from Nuget:

https://www.nuget.org/packages/Xamarin.Behaviors.Toolkit/

Want to share ideas/bugs?

I strongly encourage you to share your ideas and the bugs you’ve found. I’m always listening to goods ideas!

I also accept pulls requests that might be interesting so don’t hesitate to discuss about it too:

 

The project is still in its early stage but feel free to contact me on Twitter (@thomas_lebrun) to discuss about it!

 

Thanks and happy (Xamarin) coding!

Today, I wanted to try something new and to play a bit with sensors, on my Android device. After looking for an idea, I thought it could be interesting to implement a “ShakeDetector”, that means I wanted to be able to detect when the user shakes the device.

As I was a bit lazy, I first checked on Internet if nothing have been done and I just found different implementations of ShakeDetector for Android but written in Java, like this one: http://jasonmcreynolds.com/?p=388

Well, it does not matter: let’s see how we can adapt the Java code to get a clean C# code which allow us to detect the Shake gesture!

First step is to implement the ShakeDetector class, that will compute all the necessary stuff to detect the shake event, using the accelerometer. This class should implement SensorEventListener but this does not exists directly in Xamarin, we need to use the interface ISensorEventListener:

public class ShakeDetector : ISensorEventListener

But as soon as we try to implement the interface, we are ask to implement the following properties/methods:

image

If you try to implement them, you’ll see that they will never be called and so your code will never be called too. The reason and solution are described on this post by CheeseBaron: http://blog.ostebaronen.dk/2013/09/how-to-implement-intptr-handle-and.html

The brief explanation is that the Handle provides an Android Callable Wrapperto Android. All native Android interfaces extend IJavaObject so they will expect that to be implemented. So the simple answer is that you do not implement Handle or Disposeyourself, however you inherit from Java.Lang.Object which does that for you.

So to solve this error, you just need to modify the class ShakeDetector like this:

public class ShakeDetector : Java.Lang.Object, ISensorEventListener

Once this is done, we can continue to implement the rest of the class:

public class ShakeDetector : Java.Lang.Object, ISensorEventListener
{
    private const float SHAKE_THRESHOLD_GRAVITY = 2.7F;
    private const int SHAKE_SLOP_TIME_MS = 500;
    private const int SHAKE_COUNT_RESET_TIME_MS = 3000;

    private long mShakeTimestamp;
    private int mShakeCount;

    public delegate void OnshakeHandler(object sender, int shakeCount);
    public event OnshakeHandler Shaked;

    public void OnAccuracyChanged(Sensor sensor, SensorStatus accuracy)
    {
        // Do nothing in our case.
    }

    public void OnSensorChanged(SensorEvent e)
    {
        var x = e.Values[0];
        var y = e.Values[1];
        var z = e.Values[2];

        var gX = x / SensorManager.GravityEarth;
        var gY = y / SensorManager.GravityEarth;
        var gZ = z / SensorManager.GravityEarth;

        // gForce will be close to 1 when there is no movement.
        var gForce = Java.Lang.Math.Sqrt(gX * gX + gY * gY + gZ * gZ);

        if (!(gForce > SHAKE_THRESHOLD_GRAVITY))
            return;

        var now = JavaSystem.CurrentTimeMillis();

        // Ignore shake events too close to each other (500ms)
        if (mShakeTimestamp + SHAKE_SLOP_TIME_MS > now)
        {
            return;
        }

        // Reset the shake count after 3 seconds of no shakes
        if (mShakeTimestamp + SHAKE_COUNT_RESET_TIME_MS < now)
        {
            mShakeCount = 0;
        }

        mShakeTimestamp = now;
        mShakeCount++;

        if (this.Shaked != null)
        {
            this.Shaked(this, mShakeCount);
        }
    }
}

Note that I’ve adapt the code a bit to raise an event when the shake gesture is detected!

Now, we can continue to implement the code by registering/unregistering our new class (which implement ISensorEventListener) in the SensorManager:

[Activity(Label = "AndroidShakeDetector",
    MainLauncher = true,
    Icon = "@drawable/icon",
    ScreenOrientation = ScreenOrientation.Portrait)]
public class MainActivity : Activity
{
    private static readonly object _syncLock = new object();

    private SensorManager _sensorManager;
    private Sensor _sensor;
    private ShakeDetector _shakeDetector;

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        SetContentView(Resource.Layout.Main);

        var button = FindViewById<Button>(Resource.Id.MyButton);

        _sensorManager = (SensorManager)GetSystemService(Context.SensorService);
        _sensor = _sensorManager.GetDefaultSensor(SensorType.Accelerometer);

        _shakeDetector = new ShakeDetector();
        _shakeDetector.Shaked += (sender, shakeCount) =>
        {
            lock (_syncLock)
            {
                button.Text = shakeCount.ToString();
            }
        };
    }

    protected override void OnResume()
    {
        base.OnResume();

        _sensorManager.RegisterListener(_shakeDetector, _sensor, SensorDelay.Ui);
    }

    protected override void OnPause()
    {
        base.OnPause();

        _sensorManager.UnregisterListener(_shakeDetector);
    }
}

Be sure to allow access to the accelerometer and launch the application. As soon as you “shake” the device, you’ll see that the counter will increment and reset to 0 after 3 seconds of inactivity!

You can found the code on Github: https://github.com/ThomasLebrun/XamarinAndroidShakeDetector

 

Happy coding!

At home, I have a cool Raspberry Pi 2 and an USB LifeCam VX-6000 webcam that, for now, I don’t use for nothing. So I thought I could probably use both to create a little application that will allow me to spy anyone from it (and view the results from a simple Website).

As it’s now possible to use Windows 10 IoT Core on Raspberry, the best way for me to create that application would be to use a UWP application, developped in C#.

Basically, the code of this app will be simple: I’ll first look for the webcam and configure it:

var videodevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);

var camera = videodevices.FirstOrDefault(d => d.EnclosureLocation != null);
if (camera != null)
{
    await InitializeCameraAsync(camera);
    await InitializeAzureStuffAsync();
}

Unfortunately, after trying this code on my device, it does not work. Indeed, I was unable to get a reference to the camera After some research, the reason is simple: for now, the drivers for my Webcam are not supported (check here for the hardware compatibility list: http://ms-iot.github.io/content/en-US/win10/SupportedInterfaces.htm)

Well, I could have forgive my project but why? It’s a cool idea and we have the Universal Windows Platform: my app running on the Raspberry can also be used on any Windows 10 devices!

So I just changed the target (using my laptop instead of the PI) and, well, the code works fine: the camera is found and is correctly initialized:

private async Task InitializeCameraAsync(DeviceInformation camera)
{
    await Task.Factory.StartNew(async () =>
    {
        _mediaCapture = new MediaCapture();

        await _mediaCapture.InitializeAsync(new MediaCaptureInitializationSettings
        {
            PhotoCaptureSource = PhotoCaptureSource.VideoPreview,
            StreamingCaptureMode = StreamingCaptureMode.Video,
            VideoDeviceId = camera.Id
        });

        // Find the highest resolution available
        VideoEncodingProperties maxResolution = null;
        var max = 0;
        var resolutions = _mediaCapture.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.Photo);
        foreach (var props in resolutions)
        {
            var properties = props as VideoEncodingProperties;
            var res = properties;

            if (res?.Width * res?.Height > max)
            {
                max = (int)(res.Width * res.Height);

                maxResolution = res;
            }
        }

        await _mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.Photo, maxResolution);

        await Dispatcher.RunIdleAsync(async args =>
        {
            // Display camera preview
            CaptureElement.Source = _mediaCapture;
            await _mediaCapture.StartPreviewAsync();
        });

        _imageEncodingProperties = ImageEncodingProperties.CreateJpeg();
    });
}

The goal of the application is to take a photo from the Webcam and upload it to an Azure blob storage so we have some Azure stuff to initialize too:

private async Task InitializeAzureStuffAsync()
{
    await Task.Factory.StartNew(async () =>
    {
        var storageCredentials = new StorageCredentials(BLOB_ACCOUNT_NAME, BLOB_ACCOUNT_KEY);
        var storageAccount = new CloudStorageAccount(storageCredentials, true);

        var blobClient = storageAccount.CreateCloudBlobClient();
        _imagesContainer = blobClient.GetContainerReference("images");
        if (!await _imagesContainer.ExistsAsync())
        {
            await _imagesContainer.CreateIfNotExistsAsync();
        }

        var serviceProperties = await blobClient.GetServicePropertiesAsync();
        serviceProperties.Cors.CorsRules.Clear();
        serviceProperties.Cors.CorsRules.Add(new CorsRule
        {
            AllowedHeaders = new List<string> { "*" },
            AllowedMethods = CorsHttpMethods.Get | CorsHttpMethods.Head,
            AllowedOrigins = new List<string> { "*" },
            ExposedHeaders = new List<string> { "*" }
        });

        await blobClient.SetServicePropertiesAsync(serviceProperties);
    });
}

The code itself is pretty simple: we check if the blob container “images” exists and, if not, we create it. Then, we change the properties of the container to allow any origins to access it (otherwise, we’ll have a cross domain origin exception).

Once this part is done, we just need to take the pic from the Webcam. As we want to create a spy system, we need to take more than one pic so we’ll use a timer to take our pics:

private void OnStartWatchingButtonClick(object sender, RoutedEventArgs e)
{
    if (_timer == null)
    {
_timer = new DispatcherTimer();
_timer.Interval = new TimeSpan(0, 0, 1);
_timer.Tick += OnTimerTick;
_timer.Start();
    }

    StartWatchingButton.IsEnabled = false;
    StopWatchingButton.IsEnabled = true;
}

private async void OnTimerTick(object sender, object e)
{
    if (_mediaCapture == null)
        return;

    using (var memoryStream = new InMemoryRandomAccessStream())
    {
        try
        {
            await _mediaCapture.CapturePhotoToStreamAsync(_imageEncodingProperties, memoryStream);
            await memoryStream.FlushAsync();

            memoryStream.Seek(0);

            var array = new byte[memoryStream.Size];
            await memoryStream.ReadAsync(array.AsBuffer(), (uint)memoryStream.Size, InputStreamOptions.None);

            if (array.Length <= 0)
                return;

            var blockBlob = _imagesContainer.GetBlockBlobReference("Image.jpg");
            await blockBlob.UploadFromByteArrayAsync(array, 0, array.Length);
        }
        catch (Exception ex)
        {
            Debug.WriteLine("Exception: " + ex.Message);
        }
    }
}

Every second, the Tick event of the timer is raised and, using the CapturePhotoToStreamAsync method, we get a pic from the Webcam and we use the method from WindowsAzure.Storage to upload it to the blob storage.

So our application is up and running, pushing a pic to the blob storage every second. So we now need a way to view that pic. Let’s go for a simple AngularJS application that perform a GET request to… the URL of our image in the blog container:

"use strict";

app.controller("indexCtrl", ["$scope", function ($scope) {

    var watchIntervalId;

    $scope.isRunning = false;

    $scope.startWatching = function () {

        $scope.isRunning = true;

        watchIntervalId = setInterval(function () {
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function () {
                if (this.readyState === 4 && this.status === 200) {
                    var url = window.URL || window.webkitURL;
                    $scope.ImagePath = url.createObjectURL(this.response);
                    $scope.$apply();
                }
            }
            xhr.open("GET", "http://XXXXX.blob.core.windows.net/images/Image.jpg");
            xhr.responseType = "blob";
            xhr.send();

        }, 1000);
    }

    $scope.stopWatching = function () {

        $scope.isRunning = false;

        clearInterval(watchIntervalId);
    }
}]);

Let’s add some user interface component to get a nice app:

<!DOCTYPE html>
<html ng-app="CameraWatcherApp">
<head>
    <title>Camera Watcher</title>
    <meta charset="utf-8"/>

    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">
    <meta http-equiv="pragma" content="no-cache">

    <link rel="stylesheet" type="text/css" href="Content/bootstrap.css" />

    <script src="js/vendors/jquery/jquery-2.1.4.min.js"></script>
    <script src="js/vendors/angular/angular.min.js"></script>
    <script src="js/vendors/angular/angular-route.js"></script>

    <script src="js/app.js"></script>
    <script src="js/controllers/indexCtrl.js"></script>
</head>
<body>

<div class="container" ng-controller="indexCtrl">
    <h1>Camera Watcher <small>Your personal spy</small></h1>
    <div class="row">
        <div class="col-md-12">
            <div class="center-block">
                <img ng-hide="!isRunning" src="{{ImagePath}}" class="img-rounded" style="width: 800px; height: 600px; display: block; margin: 0 auto;" alt="Camera Watcher"/>
                <br/>
                <div class="text-center">
                    <div class="btn-group">
                        <button class="btn btn-default btn-lg" ng-click="startWatching()" ng-disabled="isRunning"><span class="glyphicon glyphicon-play" aria-hidden="true"></span> Start Watching</button>
                        <button class="btn btn-default btn-lg" ng-click="stopWatching()" ng-disabled="!isRunning"><span class="glyphicon glyphicon-stop" aria-hidden="true"></span> Stop Watching</button>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

And you’re done! Now, if you run the application, a pic will be send every second and, to view it, just launch the website:

Here is the direct link to the video: https://www.youtube.com/watch?v=XyMMdov-BGk

As you can see, it’s pretty straightforward to implement your own spy system. Of course, when the Windows 10 IoT version will support more devices, you’ll be able to use this code on the Raspberry. But, for now, you need to find another way to access to your webcam and upload the pic from it. For that, I suggest that you take a look at the great article from Laurent, which explain how to do the same upload to a blob storage from a Node JS app: http://blogs.msdn.com/b/laurelle/archive/2015/11/13/azure-iot-hub-uploading-a-webcam-picture-in-an-azure-blob-with-node-js-on-windows-and-linux.aspx?utm_content=buffercdfc0&utm_medium=social&utm_source=facebook.com&utm_campaign=buffer

 

Happy coding!

For a small side project I’m working on, I wanted to easily send push notifications to my UWP application. So I’ve decided to use the Notifications Hub (which is, in fact, a wrapper around the Microsoft Service Bus) to send the notifications.

Basically, you first need to create an application in the Store so you can access to its notifications settings:

image

With the “Package SID” and “Client Secret” settings copied, you can go to the Azure Portal to create/edit your Notification Hub (under the Service Bus section) and set the properties:

image

Now, associate your UWP application with the Store application, so the manifest file can be correctly updated with the correct values:

image

Your Notification Hub is up and running, you app is correctly associated so now, it’s time to add some code!

First step is to register your application so it can receive the notifications. For that, we need to get a push notification channel for the application and use it to register the app to the Notification Hub (after adding the WindowsAzure.Messaging.Managed Nuget package)

var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();

var hub = new NotificationHub(Constants.NOTIFICATION_HUB_PATH, Constants.NOTIFICATION_HUB_LISTEN_ENDPOINT);

await hub.RegisterNativeAsync(channel.Uri);

The notification hub path is, basically, your hub name. For the endpoint, you need to go to the Azure portal to get, from the “Dashboard” tab, the connection information:

image

By default, a notification hub has 2 different endpoints configured, each of them with different permissions:

image

As the application will only received notification, the “Listen” permission is the only one needed. So, it’s the DefaultListenSharedAccessSignature that we need to use as endpoint with the hub path.

The application is now configured, it’s time to see how to send the notifications (in my case, I’m using an Azure WebJob executing a Console app). Add the Nuget package Microsoft.Azure.NotificationHubs and you’re ready to create the NotificationHubClient object used to send the notifications:

var hub = NotificationHubClient.CreateClientFromConnectionString(Constants.NOTIFICATION_HUB_FULL_ENDPOINT, Constants.NOTIFICATION_HUB_PATH);

var windowToastTemplate = "<?xml version=\"1.0\" encoding=\"utf - 8\"?>" +
                            "<toast launch=\"fromNotification\">" +
                                "<visual>" +
                                    "<binding template=\"ToastText01\">" +
                                        "<text id = \"1\">My super notification</text>" +
                                    "</binding>" +
                                "</visual>" +
                            "</toast>";

await hub.SendWindowsNativeNotificationAsync(windowToastTemplate);

Here, you can see that I’m using SendWindowsNativeNotificationASync to send the notification to my PC (running Windows 10) but, as you can see, you can send a lot of different notifications (if you have correctly configured their settings in the Azure portal):

image  image

Also, the XML payload used for the notification is the specific part of the project: feel free to use another template and, even more, to use the new template of Windows 10 if needed : https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/Notifications

Now, you just need to schedule your Azure WebJob (thanks to Visual Studio, it’s just a right-clic on your project) and define the schedule parameters: name, frequency, etc.:

image

Now, just wait for your WebJob to run and you should receive a nice notification (toast, tile, etc.) on your device, depending of the notification type you’ve decided to use.

Bonus tip: on your Notification Hub, you can use the “DEBUG” tab to send test notifications to your devices!

image

image

As you can see, using a Notification Hub is really easy and can be implemented in a few minutes in any kind of applications!

 

Happy coding!

(WinRT) How to detect if a key modifier is pressed ?

October 13th, 2015 | Posted by Tom in .NET | Article | WinRT - (0 Comments) | Read: 325

For an application I’m working on, I needed to be able to detect if some modifiers (Control key, Alt key, Shift key, etc.) are pressed. In fact, it’s pretty simple to do, thanks to the GetKeyState method:

var shiftState = CoreWindow.GetForCurrentThread().GetKeyState(VirtualKey.Shift);
var controlState = CoreWindow.GetForCurrentThread().GetKeyState(VirtualKey.Control);

if ((shiftState & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down && (controlState & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down)
{
    //
}

And now, you’ll be able to now if user has pressed the shift key AND the control key Winking smile

 

Happy coding!

[Xamarin.iOS] How to get a multilines label ?

June 26th, 2015 | Posted by Tom in .NET | Xamarin - (0 Comments) | Read: 1,525

It’s always surprising to see how simples things doable in XAML can be a real pain when we try to do them using another language/technology.

This week, one of my customers using Xamarin asked me how to get a multilines label on iOS. After spending some time over Internet to search for a possible solution, I’ve ended with this one.

First, you need to calculate what will be the height of the label, according to the text you’ll have on it:

var labelSize = new NSString ("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque in sapien at tellus sollicitudin rutrum eu ut mi. Nunc vel cursus augue. Integer tempus sem orci, ac auctor quam bibendum non. Curabitur porttitor bibendum augue at auctor. In et cursus justo, eget finibus tortor. Donec fringilla magna dui, sed condimentum risus rhoncus in. In quis congue sem, quis elementum tellus. Cras quis orci ante.").
                    GetBoundingRect (
                        new CGSize (this.View.Frame.Width, float.MaxValue),
                        NSStringDrawingOptions.UsesLineFragmentOrigin,
                        new UIStringAttributes () { Font = UIFont.SystemFontOfSize (8) },
                        null);

As you can see, you have to specify the different properties that will be applied to the text (font size, etc.) but, most important, you have to specified the available space. Here, I indicate that the label will expand on all the width of the current view and will be able to have any height.

Once this is done, the variable labelSize will contains the desired size of the label so you’ll be able to set the height correctly:

var label = new UILabel (new CGRect(0, 0, this.View.Frame.Width, labelSize.Height))
{
    Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque in sapien at tellus sollicitudin rutrum eu ut mi. Nunc vel cursus augue. Integer tempus sem orci, ac auctor quam bibendum non. Curabitur porttitor bibendum augue at auctor. In et cursus justo, eget finibus tortor. Donec fringilla magna dui, sed condimentum risus rhoncus in. In quis congue sem, quis elementum tellus. Cras quis orci ante.",
    Font = UIFont.SystemFontOfSize (8),
    Lines = 0,
    LineBreakMode = UILineBreakMode.WordWrap
};

this.Add(label);

Here, I simply add a label to the location 0, 0 and I specified the frame width for the width and I use the labelSize.Height property to set the height.

Don’t forget to set the properties Lines to 0 and LineBreakMode to WordWrap! Indeed, set 0 to the Lines property allows the label to have an unlimited number of lines and the LineBreakMode property tells it how to break the lines (it can wrap words, characters, etc.)

Also, each text properties (font size, typeface, etc.) need to be the same as the one you used to calculate the size of the label.

 

Happy coding!

[Xamarin] Getting started with Couchbase Lite!

June 5th, 2015 | Posted by Tom in .NET | Article | Xamarin - (0 Comments) | Read: 1,047

Couchbase Lite is small, light, document-oriented (No-SQL) JSON database engine available that can be easily used in any Xamarin (iOS / Android) applications, thanks to the dedicated component: https://components.xamarin.com/view/couchbase-lite-net

 

Using Couchbase Lite is really easy and consists in only a few steps. First, we need to create a database:

var database = Manager.SharedInstance.GetDatabase("Database");

Once the database is created, we can add some documents to it (a document is something similar to a table). Each document is composed of a set of properties:

// Create a document
var properties = new Dictionary<string, object>()
{
    { "Id", Guid.NewGuid() },
    { "Title", "Getting started with Couchbase Lite!" },
    { "CreationDate", DateTime.Now },
};

var document = database.CreateDocument();
document.PutProperties(properties);

Of course, later in your application, you’ll be able to retrieve a specific document (via its Id property) to enumerate all its properties:

// Retrieve a document
var alert = new AlertDialog.Builder(this);
alert.SetTitle("CouchBase Lite!");
alert.SetPositiveButton("OK", (sender, args) => {});

var retrievedDocument = database.GetDocument(document.Id);
foreach (var property in retrievedDocument.Properties)
{
    alert.SetMessage(string.Format("Property Name: {0} - Property Value: {1}", property.Key, property.Value));
    alert.Show();
}

A document can, of course, be updated with new properties. The best way to update the document is to get its properties and update the interesting one:

// Update a document
var updatedProperties = new Dictionary<string, object>(retrievedDocument.Properties);
updatedProperties["Title"] = "This is an updated title!";

var updatedDocument = retrievedDocument.PutProperties(updatedProperties);

To delete a document (or a database), simply use the dedicated methods on the objects:

// Delete a document
updatedDocument.DeleteDocument();
database.Delete();

 

As I told you previously, Couchbase Lite is very powerful but very simple to use and to add to your application, don’t hesitate to give it a try!

 

Happy coding!

WinRT introduced a set of new APIs that developers can use to manipulate scanners (compatible with WIA, Windows Imaging Acquisition) on Windows 8.1 applications. As you’ll see, the API is pretty straightforward so let’s take a look at how to implement this feature in an app.

First, you need to create and start a watcher, used to listen for any changes on the specify devices’ kind (VideoCapture, AudioCapture, ImageScanner, etc.):

this._watcher = DeviceInformation.CreateWatcher(DeviceClass.ImageScanner);
this._watcher.Added += OnScannerAdded;
this._watcher.Start();

Here, I subscribe to the event Added to be notified when a new ImageScanner is detected by the watcher but I can also work with the events Removed, Stopped, Updated, etc.

From the event handler, I’m able to retrieve the instance of the ImageScanner that was just detected:

private async void OnScannerAdded(DeviceWatcher sender, DeviceInformation args)
{
    if (args.Name.Contains("Dell"))
    {
        this._watcher.Stop();

        var scanner = await ImageScanner.FromIdAsync(args.Id);
    }
}

Then, from the scanner, I can launch the scan of the documents, using an automatic configuration on which it’s possible to change some properties (portrait/landscape, Dpi, etc.) or by specifying which kind of scanner is used: Flatbed or Feeder:

if (scanner.IsScanSourceSupported(ImageScannerScanSource.Flatbed))
{
    // Set the scan file format to PNG, if available
    if (scanner.FlatbedConfiguration != null)
    {
        if (scanner.FlatbedConfiguration.IsFormatSupported(ImageScannerFormat.Png))
        {
            scanner.FlatbedConfiguration.Format = ImageScannerFormat.Png;
        }

        scanner.FlatbedConfiguration.DesiredResolution = new ImageScannerResolution { DpiX = 200, DpiY = 200 };
    }

    this._cancellationToken = new CancellationTokenSource();

    var scanTask = scanner.ScanFilesToFolderAsync(ImageScannerScanSource.Flatbed, Windows.Storage.ApplicationData.Current.LocalFolder);
    scanTask.Progress = (info, progressInfo) => Debug.WriteLine("Page {0}", progressInfo);

    var scanResults = await scanTask.AsTask(this._cancellationToken.Token);
}

As you can see, you can also be notified of the progression by using the Progress event of the Task!

On the scan is over, you’ll get, as a result, a collection of StorageFile corresponding to all the files that has been scanned:

for (int i = 0; i < scanResults.ScannedFiles.Count; i++)
{
    var file = scanResults.ScannedFiles[i];
}

 

As you can see, performing scanning’s operations is really simple and a lot of options can be configured. For now, I’ve used this on a flatbad scanner (and I’ve planned to use it with a different kind) and I’ve not been disappointed by the results!

 

Happy coding!

Recently, I’ve been asked by one of my customer how it could be possible, in a Xamarin.Android application, to send an email with an attachment.

After searching over Internet, I’ve managed to produce the following method:

var downloadsFolder = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads);
var filePath = Path.Combine(downloadsFolder.Path, "Demo.txt");

var createdFile = File.CreateText(filePath);
await createdFile.WriteAsync("Hello World!");
await createdFile.FlushAsync();

var file = new Java.IO.File(filePath);
file.SetReadable(true, false);

var uri = Android.Net.Uri.FromFile(file);

var email = new Intent(Intent.ActionSend);
email.PutExtra(Intent.ExtraEmail, new[] { "tom@email.com" });
email.PutExtra(Intent.ExtraSubject, "Sample email with attachment");
email.PutExtra(Intent.ExtraStream, uri);

email.SetType("message/rfc822");

this.StartActivity(Intent.CreateChooser(email, "Email"));

The most important part here is the beginning of the method. Indeed, to be able to add the attachment, it needs to be accessible to the app that will send the email. So we need to create a copy of our file in a location that can be accessible by any app so, in our case, we choose the Downloads folder.

Another interesting point is the use of the SetReadable method to indicate that the file need to be readable but to anyone and not only the file’s creator!

Finally, depending of where you create the copy, you might set the right permissions to your app:

image

Also, once your application is back to forward, don’t forget to delete the copy to clean up the Downloads folder!

 

Happy coding! :)

First of all, let me be clear: I love MVVM Light Framework, specially in Windows applications. When I started to look at Xamarin, I was very enthusiast to see that Laurent ported its Framework on that platform.

But I have to say that I was a bit disappointed when I saw it was limited (who said “light” ;)) in terms of features. One of the feature found in others MVVM Frameworks (for example in MVVM Cross) that I particularly like is the XML attributes to apply data binding.

So I’ve decided to create a small proof of concept of how you can have, in a Xamarin.Android application, a data binding engine that supports the following points:

  • Looks like the same data binding that the one we can found in XAML apps
  • Support OneWay/TwoWay bindings
  • Support commands
  • Support converters
  • Support method calls when events are raised
  • and, the last (but not the least), support data binding through XML attributes

Please, remind that this is, for now, most a prototype than something useable in your applications. In fact, all the code here works fine but I’ve not checked for memory performances, I should have used weak events, I’ve not implemented cache, etc.

All the code will be attached to the post so I’ll just provide you some pointers to the interesting parts.

At first, we need a base class for all our ViewModels:

public class BindableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Of course, this version is pretty simple and you can easily improve it. Once we have that base class, we’ll define a base activity for all the views of our application:

public abstract class BindingActivity<TViewModel> : Activity where TViewModel : BindableObject
{
    public TViewModel DataContext { get; set; }

    public int ViewLayoutResourceId { get; set; }

    protected BindingActivity(int viewLayoutResourceId)
    {
        this.ViewLayoutResourceId = viewLayoutResourceId;

        this.DataContext = ViewModelFactory.Create<TViewModel>();
    }

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        this.SetContentView(this.ViewLayoutResourceId);

        BindingEngine.Initialize(this);
    }
}

As you can see, the BindingActivity expose a DataContext property (as we found in XAML) and initialize the binding engine. To use it, you just have to inherit from that class and pass the type of ViewMode:

[Activity(Label = "SampleBindingEngine", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : BindingActivity<MainViewModel>
{
    int _count = 1;

    public MainActivity()
        : base(Resource.Layout.Main)
    {
    }
}

The ViewModel is composed by the following elements:

public class MainViewModel : BindableObject
{
    private bool _isBusy;

    public bool IsBusy
    {
        get { return _isBusy; }
        set
        {
            _isBusy = value;

            this.OnPropertyChanged();
        }
    }

    private string _sampleText;
    public string SampleText
    {
        get { return _sampleText; }
        set
        {
            _sampleText = value;

            this.OnPropertyChanged();

            if (this.ButtonClickCommand != null)
            {
                this.ButtonClickCommand.RaiseCanExecuteChanged();
            }
        }
    }

    public RelayCommand ButtonClickCommand { get; set; }

    public MainViewModel()
    {
        this.SampleText = "Hey, Xamarin World!";

        this.ButtonClickCommand = new RelayCommand(o =>
        {
            this.SampleText = "Text Changed from First Command!";
        },
        o => !string.IsNullOrWhiteSpace(this.SampleText));
    }

    private void ClickOnButton()
    {
        this.SampleText = "Text Changed from Method!";
    }
}

This is on that class, BindingEngine, that most of the job is done:

private const string ViewLayoutResourceIdPropertyName = "ViewLayoutResourceId";
public static void Initialize<TViewModel>(BindingActivity<TViewModel> bindingActivity) where TViewModel : BindableObject
{
    // TODO
}

First, we need to get the XML elements that composed the view;

List<XElement> xmlElements = null;

// Find the value of the ViewLayoutResourceId property
var viewLayoutResourceIdProperty = bindingActivity.GetType().GetProperty(ViewLayoutResourceIdPropertyName);
var viewLayoutResourceId = (int)viewLayoutResourceIdProperty.GetValue(bindingActivity);

if (viewLayoutResourceId > -1)
{
    // Load the XML elements of the view
    xmlElements = GetViewAsXmlElements(bindingActivity, viewLayoutResourceId);
}

/// <summary>
/// Returns the current view (activity) as a list of XML element.
/// </summary>
/// <typeparam name="TViewModel">The type of the ViewModel associated to the activity.</typeparam>
/// <param name="bindingActivity">The current activity we want to get as a list of XML elements.</param>
/// <param name="viewLayoutResourceId">The id corresponding to the layout.</param>
/// <returns>A list of XML elements which represent the XML layout of the view.</returns>
private static List<XElement> GetViewAsXmlElements<TViewModel>(BindingActivity<TViewModel> bindingActivity, int viewLayoutResourceId) where TViewModel : BindableObject
{
    List<XElement> xmlElements;

    using (var viewAsXmlReader = bindingActivity.Resources.GetLayout(viewLayoutResourceId))
    {
        using (var sb = new StringBuilder())
        {
            while (viewAsXmlReader.Read())
            {
                sb.Append(viewAsXmlReader.ReadOuterXml());
            }

            var viewAsXDocument = XDocument.Parse(sb.ToString());
            xmlElements = viewAsXDocument.Descendants().ToList();
        }
    }

    return xmlElements;
}

Then, we’ll check if there are some XML elements that contains our “Binding” attribute and, if that’s true, we’ll get the current view a a list of .NET objects:

private static readonly XName BindingOperationXmlNamespace = XNamespace.Get("http://schemas.android.com/apk/res-auto") + "Binding";

// If there is at least one 'Binding' attribute set in the XML file, get the view as objects
if (xmlElements != null && xmlElements.Any(xe => xe.Attribute(BindingOperationXmlNamespace) != null))
{
    viewElements = GetViewAsObjects(bindingActivity);
}

/// <summary>
/// Returns the current view (activity) as a list of .NET objects.
/// </summary>
/// <typeparam name="TViewModel">The type of the ViewModel associated to the activity.</typeparam>
/// <param name="bindingActivity">The current activity we want to get as a list of XML elements.</param>
/// <returns>A list of .NET objects which composed the view.</returns>
private static List<View> GetViewAsObjects<TViewModel>(BindingActivity<TViewModel> bindingActivity) where TViewModel : BindableObject
{
    // Get the objects on the view
    var rootView = bindingActivity.Window.DecorView.FindViewById(Resource.Id.Content);

    return GetAllChildrenInView(rootView, true);
}

/// <summary>
/// Recursive method which returns the list of children contains in a view.
/// </summary>
/// <param name="rootView">The root/start view from which the analysis is performed.</param>
/// <param name="isTopRootView">True is the current root element is, in fact, the top view.</param>
/// <returns>A list containing all the views with their childrens.</returns>
private static List<View> GetAllChildrenInView(View rootView, bool isTopRootView = false)
{
    if (!(rootView is ViewGroup))
    {
        return new List<View> { rootView };
    }

    var childrens = new List<View>();

    var viewGroup = (ViewGroup)rootView;

    for (int i = 0; i < viewGroup.ChildCount; i++)
    {
        var child = viewGroup.GetChildAt(i);

        var childList = new List<View>();
        if (isTopRootView)
        {
            childList.Add(child);
        }

        childList.AddRange(GetAllChildrenInView(child));

        childrens.AddRange(childList);
    }

    return childrens;
}

Now, we’ll extract all the binding operations implemented in the XML file:

if (xmlElements != null && xmlElements.Any() && viewElements != null && viewElements.Any())
{
    // Get all the binding operations inside the XML file.
    var bindingOperations = ExtractBindingOperationsFromLayoutFile(xmlElements, viewElements);
    if (bindingOperations != null && bindingOperations.Any())
    {
        // Find the value of the DataContext property (which is, in fact, our ViewModel)
        var viewModel = bindingActivity.DataContext as BindableObject;
        if (viewModel != null)
        {
            // TODO
        }
    }
}

/// <summary>
/// Extract the Binding operations (represent by the Binding="" attribute in the XML file).
/// </summary>
/// <param name="xmlElements">The list of XML elements from which we want to extract the Binding operations.</param>
/// <param name="viewElements">The list of .NET objects corresponding to the elements of the view.</param>
/// <returns>A list containing all the binding operations (matching between the Source property, the Target property, the Control bound to the .NET property and the Mode of the binding).</returns>
private static List<BindingOperation> ExtractBindingOperationsFromLayoutFile(List<XElement> xmlElements, List<View> viewElements)
{
    var bindingOperations = new List<BindingOperation>();

    for (int i = 0; i < xmlElements.Count; i++)
    {
        var currentXmlElement = xmlElements.ElementAt(i);

        if (currentXmlElement.Attributes(BindingOperationXmlNamespace).Any())
        {
            var xmlBindings = currentXmlElement.Attributes(BindingOperationXmlNamespace);

            foreach (var xmlBindingAttribute in xmlBindings)
            {

                var xmlBindingValue = xmlBindingAttribute.Value;

                if (!xmlBindingValue.StartsWith("{") || !xmlBindingValue.EndsWith("}"))
                {
                    throw new InvalidOperationException(string.Format("The following XML binding operation is not well formatted, it should start with '{{' and end with '}}:'{0}{1}", Environment.NewLine, xmlBindingValue));
                }

                var xmlBindingOperations = xmlBindingValue.Split(';');

                foreach (var bindingOperation in xmlBindingOperations)
                {
                    if (!bindingOperation.Contains(","))
                    {
                        throw new InvalidOperationException(string.Format("The following XML binding operation is not well formatted, it should contains at least one ',' between Source and Target:{0}{1}", Environment.NewLine, xmlBindingValue));
                    }

                    var bindingSourceValueRegex = new Regex(@"Source=(\w+)");
                    var bindingSourceValue = bindingSourceValueRegex.Match(bindingOperation).Groups[1].Value;

                    var bindingTargetValueRegex = new Regex(@"Target=(\w+)");
                    var bindingTargetValue = bindingTargetValueRegex.Match(bindingOperation).Groups[1].Value;

                    var bindingConverterValueRegex = new Regex(@"Converter=(\w+)");
                    var bindingConverterValue = bindingConverterValueRegex.Match(bindingOperation).Groups[1].Value;

                    // Converter parameter support using more than just a word.
                    var bindingConverterParameterValueRegex = new Regex(@"ConverterParameter='(\w+\s(.\w+)+)");
                    var bindingConverterParameterValue = bindingConverterParameterValueRegex.Match(bindingOperation).Groups[1].Value;

                    var bindingModeValue = BindingMode.OneWay;

                    var bindingModeValueRegex = new Regex(@"Mode=(\w+)");
                    var bindingModeValueRegexMatch = bindingModeValueRegex.Match(bindingOperation);

                    if (bindingModeValueRegexMatch.Success)
                    {
                        if (!System.Enum.TryParse(bindingModeValueRegexMatch.Groups[1].Value, true, out bindingModeValue))
                        {
                            throw new InvalidOperationException(string.Format("The Mode property of the following XML binding operation is not well formatted, it should be 'OneWay' or 'TwoWay':{0}{1}", Environment.NewLine, xmlBindingValue));
                        }
                    }

                    bindingOperations.Add(new BindingOperation { Control = viewElements.ElementAt(i), Source = bindingSourceValue, Target = bindingTargetValue, Converter = bindingConverterValue, ConverterParameter = bindingConverterParameterValue, Mode = bindingModeValue });
                }

            }
        }
    }

    return bindingOperations;
}

And then, we just need to analyse each binding operation to get the Mode, Source and Target propertied so we can setup the binding. For example, here is how we can setup a binding between a command (or a method) and an event:

var sourceProperty = typeof(TViewModel).GetProperty(bindingOperation.Source);

var bindingEvent = bindingOperation.Control.GetType().GetEvent(bindingOperation.Target);
if (bindingEvent != null)
{
    // The target is an event of the control

    if (sourceProperty != null)
    {
        // We need to ensure that the bound property implements the interface ICommand so we can call the "Execute" method
        var command = sourceProperty.GetValue(viewModel) as ICommand;
        if (command == null)
        {
            throw new InvalidOperationException(string.Format("The source property {0}, bound to the event {1}, needs to implement the interface ICommand.", bindingOperation.Source, bindingEvent.Name));
        }

        // Add an event handler to the specified event to execute the command when event is raised
        var executeMethodInfo = typeof(ICommand).GetMethod("Execute", new[] { typeof(object) });

        AddHandler(bindingOperation.Control, bindingOperation.Target, () =>
        {
            if (!_preventUpdateForSourceProperty)
            {
                executeMethodInfo.Invoke(command, new object[] { null });
            }
        });

        // Add an event handler to manage the CanExecuteChanged event of the command (so we can disable/enable the control attached to the command)
        var currentControl = bindingOperation.Control;

        var enabledProperty = currentControl.GetType().GetProperty("Enabled");
        if (enabledProperty != null)
        {
            enabledProperty.SetValue(currentControl, command.CanExecute(null));

            AddHandler(command, "CanExecuteChanged", () => enabledProperty.SetValue(currentControl, command.CanExecute(null)));
        }
    }
    else
    {
        // If the Source property of the ViewModel is not a 'real' property, check if it's a method
        var sourceMethod = typeof(TViewModel).GetMethod(bindingOperation.Source, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
        if (sourceMethod != null)
        {
            if (sourceMethod.GetParameters().Length > 0)
            {
                // We only support calls to methods without parameters
                throw new InvalidOperationException(string.Format("Method {0} should not have any parameters to be called when event {1} is raised.", sourceMethod.Name, bindingEvent.Name));
            }

            // If it's a method, add a event handler to the specified event to execute the method when event is raised
            AddHandler(bindingOperation.Control, bindingOperation.Target, () =>
            {
                if (!_preventUpdateForSourceProperty)
                {
                    sourceMethod.Invoke(viewModel, null);
                }
            });
        }
        else
        {
            throw new InvalidOperationException(string.Format("No property or event named {0} found to bint it to the event {1}.", bindingOperation.Source, bindingEvent.Name));
        }
    }
}

Using the binding feature from an AXML file is as simple as adding a new XML attribute matching the source property to the target property. Here are a few example of what is supported for now:

<!-- Simple OneWay binding -->
    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/Hello"
        local:Binding="{Source=SampleText, Target=Text}" />
<!-- Simple TwoWay binding -->
    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/Hello"
        local:Binding="{Source=SampleText, Target=Text, Mode=TwoWay}" />
<!-- Binding an event to a command -->
    <Button
        android:id="@+id/MyButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Change EditText From Command"
        local:Binding="{Source=ButtonClickCommand, Target=Click}" />
    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/Hello"
        local:Binding="{Source=SampleText2, Target=Text, Mode=TwoWay;Source=TextCommand, Target=TextChanged}" />
<!-- Binding an event to a method -->
    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Change EditText From Method"
        local:Binding="{Source=ClickOnButton, Target=Click}" />
<!-- Binding with a converter -->
    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/Hello"
        local:Binding="{Source=SampleBool, Target=Text, Mode=TwoWay, Converter=BooleanToStringConverter}" />
<!-- Binding with a converter & converter parameter -->
    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/Hello"
        local:Binding="{Source=SampleBool, Target=Text, Mode=TwoWay, Converter=BooleanToStringConverter, ConverterParameter='You can put any string here'}" />

I highly recommend you to take a look at the source code to see what can be done, how to setup TwoWay binding, etc. Also, for now, the engine does not support nested source properties (MyObject.MyFirstProperty.MySecondProperty) but this is something that I plan to implement as soon as possible (and if anybody think it’s a good idea/engine)!

 

The source code is available here for now but, based on feedbacks I have, it’s possible that I put it on Github to continue the development (and to allow pull requests).

So guys, what do you think about it ? Should I continue developing this binding engine ? Feel free to keep in touch with me by email, Twitter or in the comments to discuss about it!

 

Happy coding!