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

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

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: 666

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!

[NodeJS] An extended version of OmxDirector

February 23rd, 2015 | Posted by Tom in Article | NodeJS - (0 Comments) | Read: 238

OmxDirector is a NodeJS module, written by Alessandro Pezzato, that allows any NodeJS application to control OmxPlayer, a video player specifically made for the Raspberry Pi’s.

Unfortunately, the current version of OmxDirector has a limited numbers of features implemented.

So I’ve created a fork of the official version and extended the module to add the following features:

  • Ability to play a remote (HTTP) file
  • Ability to go backwards (-30 seconds)
  • Ability to go forwards (+30 seconds)

 

Using the new features is really easy and involve to call some little Javascript fonctions:

omx.play('http://www.server.com/video.mp4');

omx.backwards();

omx.forwards();

 

I’ll try to add more features to be able to cover all the features of OmxPlayer but, in the meantime, feel free to contact me (@thomas_lebrun on Twitter) if you want to discuss about it!

 

Happy coding!

In my previous article, I’ve explained how to use Roslyn to implement a feature available in Resharper that allows you to easily change the modifier(s) of a property.

Today, we’ll see how we can implement another great feature: we’ll allow the user to easily replace a type by “var” in the declaration of a variable:

image

To do this, we’ll use a diagnostic analyser that will analyse our syntax tree:

public override void Initialize(AnalysisContext context)
{
    context.RegisterSyntaxTreeAction(DetectInitializedVariableDeclaration);
}

The method will inspect the syntax tree to detect all the element of type VariableDeclarationSyntax.  For each element, we’ll retrieve the EqualsValueClauseSyntax object and, if there is one (meaning the variable has been initialized), we’ll add our diagnostic on the type element:

private async static void DetectInitializedVariableDeclaration(SyntaxTreeAnalysisContext context)
{
    var root = await context.Tree.GetRootAsync();
    var variableDeclarationSyntaxElements = root.DescendantNodesAndSelf().OfType<VariableDeclarationSyntax>();

    if (variableDeclarationSyntaxElements.Any())
    {
        for (int i = 0; i < variableDeclarationSyntaxElements.Count(); i++)
        {
            var variableDeclaration = variableDeclarationSyntaxElements.ElementAt(i);

            var equalsValueClauseSyntaxElements = variableDeclaration.DescendantNodesAndSelf().OfType<EqualsValueClauseSyntax>();
            if (equalsValueClauseSyntaxElements.Any())
            {
                foreach (var equalsValueClause in equalsValueClauseSyntaxElements)
                {
                    var nodeType = variableDeclaration.DescendantNodesAndSelf().OfType<PredefinedTypeSyntax>().FirstOrDefault();
                    if (nodeType != null && !nodeType.IsVar)
                    {
                        // Add "contextual" menu to use 'var' instead of the real type
                        var diagnostic = Diagnostic.Create(UseVarRule, nodeType.GetLocation());

                        context.ReportDiagnostic(diagnostic);
                    }
                }
            }
        }
    }
}

The code fix provider associated is pretty simple:

public sealed override async Task ComputeFixesAsync(CodeFixContext context)
{
    var diagnostic = context.Diagnostics.First();

    var diagnosticSpan = diagnostic.Location.SourceSpan;

    var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

    var predefinedType = root.FindNode(diagnostic.Location.SourceSpan) as PredefinedTypeSyntax;
    if (predefinedType != null)
    {
        var variableDeclarationSyntaxElement = predefinedType.Parent as VariableDeclarationSyntax;
        if (variableDeclarationSyntaxElement != null)
        {
            context.RegisterFix(CodeAction.Create("Use 'var'", c => UseVarKeywordAsync(context.Document, variableDeclarationSyntaxElement, c)), diagnostic);
        }
    }
}

The method “UseVarKeyword” will perform all the magic here: it will create a copy of our element by adding the previous trivia and changing the type (using ‘var’ instead of the actual type).

private static async Task<Document> ReplaceNodeInDocumentAsync(
    Document document,
    SyntaxNode oldNode,
    SyntaxNode newNode,
    CancellationToken cancellationToken)
{
    var root = await document.GetSyntaxRootAsync(cancellationToken);
    var newRoot = root.ReplaceNode(oldNode, newNode);

    return document.WithSyntaxRoot(newRoot);
}

private static async Task<Document> UseVarKeywordAsync(
    Document document,
    VariableDeclarationSyntax variableDeclarationSyntaxElement,
    CancellationToken cancellationToken)
{
    // var is not a real keyword in C# so create an identifier named 'var': http://stackoverflow.com/questions/14777133/declaring-var-variables-with-roslyn-sept-2012-ctp
    var newVariableDeclarationSyntaxElement = variableDeclarationSyntaxElement.WithType(SyntaxFactory.IdentifierName("var "));
    newVariableDeclarationSyntaxElement = newVariableDeclarationSyntaxElement.WithLeadingTrivia(variableDeclarationSyntaxElement.GetLeadingTrivia());

    return await ReplaceNodeInDocumentAsync(document, variableDeclarationSyntaxElement, newVariableDeclarationSyntaxElement, cancellationToken);
}

Note that ‘var’ is not a real C# keyword so we’ll need to create a “custom” identifier named ‘var’.

Once executed, the extension allows us to have the following:

image

image

As you can see, using Roslyn, it’s really easy to add your custom rules to Visual Studio!

 

Happy coding!

One of the feature that I like in Resharper is the one that allow you to easily change the modifiers of any properties:

image

Thanks to Visual Studio 2015 and Roslyn, it’s now possible to provide the same kind of experience using a custom extension.

To implement this feature, we need to create a diagnostic analyser and a code fix provider. So let’s take a look at the diagnostic analyser:

public class CSharpEssentialsAnalyzer : DiagnosticAnalyzer
{
    public const string DiagnosticId = "CSharpEssentials";

    #region Change Modifier

    internal const string ChangeModifierRuleTitle = "Change modifier";
    internal const string ChangeModifierRuleMessageFormat = "Change modifier for '{0}'";
    internal const string ChangeModifierRuleCategory = "Refactoring";

    internal static DiagnosticDescriptor ChangePropertyModifierRule = new DiagnosticDescriptor(
        DiagnosticId,
        ChangeModifierRuleTitle,
        ChangeModifierRuleMessageFormat,
        ChangeModifierRuleCategory,
        DiagnosticSeverity.Info,
        isEnabledByDefault: true);

    #endregion

    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
    {
        get
        {
            return ImmutableArray.Create(ChangePropertyModifierRule);
        }
    }

    public override void Initialize(AnalysisContext context)
    {
        context.RegisterSymbolAction(AnalyzePropertySymbol, SymbolKind.Property);
    }

    private static void AnalyzePropertySymbol(SymbolAnalysisContext context)
    {
        var propertySymbol = context.Symbol as IPropertySymbol;
        if (propertySymbol != null)
        {
            // Add "contextual" menu to change property modifiers.
            var diagnostic = Diagnostic.Create(ChangePropertyModifierRule, propertySymbol.Locations[0], propertySymbol.Name);

            context.ReportDiagnostic(diagnostic);
        }
    }
}

The code is simple to understand: on the Initiliaze method, we register a action that will be called for each property of the source code (of the current document). On that action, we check if we are really on a property (this should always be the case but it’s still a good thing to check) and we add a diagnostic at the property’s location. A diagnostic is the way to add an indicator on Visual Studio’s margin, telling “hey! there is something to check here”. This can be an error, a warning or an information.

Running the previous code, we can see the indicator:

image

By changing the severity of the rule that’s broken, we can change the way the indicator is shown. Here is the result if we specify a severity of kind “Error” (the property’s identifier is underlined in red)

image

Now that the indicator (the yellow light bulb) is show, we need to indicate to the user the different kind of fixes he can do. So we have to implement a Code fix provider (by inherited from the class CodeFixProvider):

public class CSharpEssentialsCodeFixProvider : CodeFixProvider
{
    private SyntaxToken _whitespaceToken =
        SyntaxFactory.Token(SyntaxTriviaList.Create(SyntaxFactory.Space), SyntaxKind.StringLiteralToken, SyntaxTriviaList.Empty);

    public sealed override ImmutableArray<string> GetFixableDiagnosticIds()
    {
        return ImmutableArray.Create(CSharpEssentialsAnalyzer.DiagnosticId);
    }

    public sealed override FixAllProvider GetFixAllProvider()
    {
        return WellKnownFixAllProviders.BatchFixer;
    }

    public sealed override async Task ComputeFixesAsync(CodeFixContext context)
    {
        var diagnostic = context.Diagnostics.First();
        var diagnosticSpan = diagnostic.Location.SourceSpan;

        var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

        var property = root.FindNode(diagnosticSpan) as PropertyDeclarationSyntax;
        if (property != null)
        {
            if (property.Modifiers.Any(m => m.CSharpKind() == SyntaxKind.PublicKeyword))
            {
                context.RegisterFix(
                    CodeAction.Create("To private", c => ReplacePropertyModifierAsync(context.Document, property, SyntaxKind.PrivateKeyword, c)),
                    diagnostic);

                context.RegisterFix(
                    CodeAction.Create("To protected", c => ReplacePropertyModifierAsync(context.Document, property, SyntaxKind.ProtectedKeyword, c)),
                    diagnostic);

                context.RegisterFix(
                    CodeAction.Create("To internal", c => ReplacePropertyModifierAsync(context.Document, property, SyntaxKind.InternalKeyword, c)),
                    diagnostic);
            }
            else if (property.Modifiers.Any(m => m.CSharpKind() == SyntaxKind.PrivateKeyword))
            {
                context.RegisterFix(
                    CodeAction.Create("To public", c => ReplacePropertyModifierAsync(context.Document, property, SyntaxKind.PublicKeyword, c)),
                    diagnostic);

                context.RegisterFix(
                    CodeAction.Create("To protected", c => ReplacePropertyModifierAsync(context.Document, property, SyntaxKind.ProtectedKeyword, c)),
                    diagnostic);

                context.RegisterFix(
                    CodeAction.Create("To internal", c => ReplacePropertyModifierAsync(context.Document, property, SyntaxKind.InternalKeyword, c)),
                    diagnostic);
            }
            else if (property.Modifiers.Any(m => m.CSharpKind() == SyntaxKind.ProtectedKeyword))
            {
                context.RegisterFix(
                    CodeAction.Create("To public", c => ReplacePropertyModifierAsync(context.Document, property, SyntaxKind.PublicKeyword, c)),
                    diagnostic);

                context.RegisterFix(
                    CodeAction.Create("To private", c => ReplacePropertyModifierAsync(context.Document, property, SyntaxKind.PrivateKeyword, c)),
                    diagnostic);

                context.RegisterFix(
                    CodeAction.Create("To internal", c => ReplacePropertyModifierAsync(context.Document, property, SyntaxKind.InternalKeyword, c)),
                    diagnostic);
            }
            else if (property.Modifiers.Any(m => m.CSharpKind() == SyntaxKind.InternalKeyword))
            {
                context.RegisterFix(
                    CodeAction.Create("To public", c => ReplacePropertyModifierAsync(context.Document, property, SyntaxKind.PublicKeyword, c)),
                    diagnostic);

                context.RegisterFix(
                    CodeAction.Create("To private", c => ReplacePropertyModifierAsync(context.Document, property, SyntaxKind.PrivateKeyword, c)),
                    diagnostic);

                context.RegisterFix(
                    CodeAction.Create("To protected", c => ReplacePropertyModifierAsync(context.Document, property, SyntaxKind.ProtectedKeyword, c)),
                    diagnostic);
            }

            if (!property.Modifiers.Any(m => m.CSharpKind() == SyntaxKind.VirtualKeyword))
            {
                context.RegisterFix(
                    CodeAction.Create("To virtual", c => AddPropertyModifierAsync(context.Document, property, SyntaxKind.VirtualKeyword, c)),
                    diagnostic);
            }
            else if (property.Modifiers.Any(m => m.CSharpKind() == SyntaxKind.VirtualKeyword))
            {
                context.RegisterFix(
                    CodeAction.Create("To non virtual", c => RemovePropertyModifierAsync(context.Document, property, SyntaxKind.VirtualKeyword, c)),
                    diagnostic);
            }
        }
    }

    private async Task<Document> AddPropertyModifierAsync(
        Document document,
        PropertyDeclarationSyntax property,
        SyntaxKind propertyModifier,
        CancellationToken cancellationToken)
    {
        //var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
        //var propertySymbol = semanticModel.GetDeclaredSymbol(property, cancellationToken);

        var newProperty = property.AddModifiers(SyntaxFactory.Token(propertyModifier), _whitespaceToken);

        return await ReplacePropertyInDocumentAsync(document, property, newProperty, cancellationToken);
    }

    private async Task<Document> RemovePropertyModifierAsync(
        Document document,
        PropertyDeclarationSyntax property,
        SyntaxKind propertyModifier,
        CancellationToken cancellationToken)
    {
        var syntaxTokenList = new SyntaxTokenList();

        var existingModifiersWithoutSpecifiedModifier = property.Modifiers.Where(m => m.CSharpKind() != propertyModifier);
        foreach (var item in existingModifiersWithoutSpecifiedModifier)
        {
            syntaxTokenList = syntaxTokenList.Add(item);
        }

        var newProperty = SyntaxFactory.PropertyDeclaration(new SyntaxList<AttributeListSyntax>(), syntaxTokenList, property.Type, null, property.Identifier, property.AccessorList);

        return await ReplacePropertyInDocumentAsync(document, property, newProperty, cancellationToken);
    }

    private async Task<Document> ReplacePropertyModifierAsync(
        Document document,
        PropertyDeclarationSyntax property,
        SyntaxKind propertyModifier,
        CancellationToken cancellationToken)
    {
        var previousWhiteSpacesToken = SyntaxFactory.Token(property.GetLeadingTrivia(), SyntaxKind.StringLiteralToken, SyntaxTriviaList.Empty);

        var newProperty = property.WithModifiers(SyntaxTokenList.Create(previousWhiteSpacesToken)
            .Add(SyntaxFactory.Token(propertyModifier))
            .Add(_whitespaceToken));

        if (property.Modifiers.Any(m => m.CSharpKind() == SyntaxKind.VirtualKeyword))
        {
            newProperty = newProperty.AddModifiers(SyntaxFactory.Token(SyntaxKind.VirtualKeyword), _whitespaceToken);
        }

        return await ReplacePropertyInDocumentAsync(document, property, newProperty, cancellationToken);
    }

    private static async Task<Document> ReplacePropertyInDocumentAsync(
        Document document,
        PropertyDeclarationSyntax property,
        PropertyDeclarationSyntax newProperty,
        CancellationToken cancellationToken)
    {
        var root = await document.GetSyntaxRootAsync(cancellationToken);
        var newRoot = root.ReplaceNode(property, new[] { newProperty });

        return document.WithSyntaxRoot(newRoot);
    }
}

This class might be a bit more complicated but, in fact, it’s pretty simple. The method ComputeFixesAsync is used to show to the user the available fixes that he can used. To display this fixes, we need to get the different diagnostics of the location we are and show the fixes available for the dedicated diagnostics.

In our case, we want to change the modifiers of the property we first need to check the current modifier and show the fixes:

if (property.Modifiers.Any(m => m.CSharpKind() == SyntaxKind.PublicKeyword))
{
    context.RegisterFix(
        CodeAction.Create("To private", c => ReplacePropertyModifierAsync(context.Document, property, SyntaxKind.PrivateKeyword, c)),
        diagnostic);

    context.RegisterFix(
        CodeAction.Create("To protected", c => ReplacePropertyModifierAsync(context.Document, property, SyntaxKind.ProtectedKeyword, c)),
        diagnostic);

    context.RegisterFix(
        CodeAction.Create("To internal", c => ReplacePropertyModifierAsync(context.Document, property, SyntaxKind.InternalKeyword, c)),
        diagnostic);
}

In a code fix provider class, we have access to the current document and we’ll use it to show the preview of what will be the result’s code if the user select a dedicated fix. We can’t just update the current document so we need to create a copy of the document and edit it on the fly:

private async Task<Document> ReplacePropertyModifierAsync(
    Document document,
    PropertyDeclarationSyntax property,
    SyntaxKind propertyModifier,
    CancellationToken cancellationToken)
{
    var previousWhiteSpacesToken = SyntaxFactory.Token(property.GetLeadingTrivia(), SyntaxKind.StringLiteralToken, SyntaxTriviaList.Empty);

    var newProperty = property.WithModifiers(SyntaxTokenList.Create(previousWhiteSpacesToken)
        .Add(SyntaxFactory.Token(propertyModifier))
        .Add(_whitespaceToken));

    if (property.Modifiers.Any(m => m.CSharpKind() == SyntaxKind.VirtualKeyword))
    {
        newProperty = newProperty.AddModifiers(SyntaxFactory.Token(SyntaxKind.VirtualKeyword), _whitespaceToken);
    }

    return await ReplacePropertyInDocumentAsync(document, property, newProperty, cancellationToken);
}

private static async Task<Document> ReplacePropertyInDocumentAsync(
    Document document,
    PropertyDeclarationSyntax property,
    PropertyDeclarationSyntax newProperty,
    CancellationToken cancellationToken)
{
    var root = await document.GetSyntaxRootAsync(cancellationToken);
    var newRoot = root.ReplaceNode(property, new[] { newProperty });

    return document.WithSyntaxRoot(newRoot);
}

As you can see, changing a property’s modifier is simple: we copy the property and add the specified modifier (if the “virtual” modifier has been already added, we copy it again). Note that we also add a whitespace after the modifier so the syntax will be respected.

Once executed, the code will allow to display the following fixes:

image

image

When user put its mouse over a fix, we can see a preview of the fix (the red lines consists of the code that will be removed and the green lines are the code that will be added):

image

image

Of course, the “Preview changes” feature works here too:

image

The good point is that we just modified the modifiers without changing the accessors. So if you have dedicated code in the get/set, it will be persisted:

image

 

As you can see, Roslyn give you a powerful object model to manipulate your code. You will now be able to create powerful extensions in a simple manner!

 

Happy coding!

[Xamarin] Scanning QRCode in a Xamarin.Forms application

September 29th, 2014 | Posted by Tom in .NET | Article | Xamarin - (0 Comments) | Read: 4,046

Scanning QRCodes (or barcodes) in a Xamarin.Forms application is really easy thanks to a well-know project ZXing, that has been ported to Xamarin (and for all the devices: iOS, Android and Windows Phone).

 

To implement the feature, first add a reference to the ZXing component to your projects. Then, as always, we need to find a way to communicate between the Forms project (that contains the logic) and the various UI projects. To solve this, we’ll used the DependencyService to register an interface and create the various implementations.

The interface is pretty simple:

public interface IQrCodeScanningService
{
    Task<string> ScanAsync();
}

And here is the implementation for the Windows Phone project:

public class QrCodeScanningService : IQrCodeScanningService
{
    public async Task<string> ScanAsync()
    {
        var scanner = new ZXing.Mobile.MobileBarcodeScanner(App.RootFrame.Dispatcher);
        var scanResults = await scanner.Scan();

        return scanResults.Text;
    }
}

And now, let’s take a look to the implementation for the Android project (of course, it’s also possible to create an iOS implementation):

public class QrCodeScanningService : IQrCodeScanningService
{
    public async Task<string> ScanAsync()
    {
        var scanner = new ZXing.Mobile.MobileBarcodeScanner(Application.Context);
        var scanResults = await scanner.Scan();

        return scanResults.Text;
    }
}

As you can see, each version is particular (the constructor of the MobileBarcodeScanner takes a different parameters, according to the platform).

For each implementation, don’t forget to add the Dependency attribute so the DependencyService can register the interface and the implementation:

// Windows Phone
[assembly: Dependency (typeof(QrCodeScanningService))]
namespace QrCodeScanningWithXamarin.WinPhone.Helpers

// Android
[assembly: Dependency(typeof(QrCodeScanningService))]
namespace QrCodeScanningWithXamarin.Droid.Helpers

And now, in the Forms project (Shared or portable), we can use the DependencyService to retrieve the instance of the class that implement our interface:

var scanButton = new Button
{
    Text = "Launch scan"
};
scanButton.Clicked += async (sender, args) =>
{
    var url = await DependencyService.Get<IQrCodeScanningService>().ScanAsync();

    Device.OpenUri(new Uri(url));
};

Launch your application and click on the button to display the overlay allowing the user to scan a QRCode or Barcode. Once the view appears on the screen, click on it and, after the autofocus is performed, the scan is done and the results are returned so you can use them (display them, launch the URL, etc.)

 

Happy coding!

Since Windows 8, it’s possible to share uris, files, images, etc. using the Share contract:

var dataTransferManager = DataTransferManager.GetForCurrentView();
dataTransferManager.DataRequested += this.ShareStorageItemsTextHandler;

private async void ShareStorageItemsTextHandler(DataTransferManager sender, DataRequestedEventArgs args)
{
    DataRequest request = args.Request;

    request.Data.Properties.Title = "Sample";
    request.Data.Properties.Description = "Description";
}

Thanks to the unification of Windows 8.1 and Windows Phone 8.1, we can now do the same to share items on Windows Phone.

While I was testing that on an Windows Phone 8.1 (WinRT) application, I found that if you want to share an image, you’ll need to share the StorageFile instead. Indeed, the following will not work:

private async void ShareStorageItemsTextHandler(DataTransferManager sender, DataRequestedEventArgs args)
{
    DataRequest request = args.Request;

    request.Data.Properties.Title = "Sample";
    request.Data.Properties.Description = "Description";

    var deferral = request.GetDeferral();

    try
    {
        var fileToShare = await this.GetImageFileAsync("Sample.jpg");

        request.Data.Properties.Thumbnail = RandomAccessStreamReference.CreateFromStream(fileToShare);
        request.Data.SetBitmap(RandomAccessStreamReference.CreateFromStream(fileToShare));
    }
    finally
    {
        deferral.Complete();
    }
}

Well, in fact, if you try to share, you’ll see that it’s working except that the image is not displayed/used. This is due to the fact that when an application implement the Share contract (in receive mode), it needs to indicate which file format it’s able to manage: uris, bitmap, file, text, etc. The native Windows Phone’s apps does not seems to manage the Bitmap format of the Share contract so you’ll need to used the following version:

private async void ShareStorageItemsTextHandler(DataTransferManager sender, DataRequestedEventArgs args)
{
    DataRequest request = args.Request;

    request.Data.Properties.Title = "Sample";
    request.Data.Properties.Description = "Description";

    var deferral = request.GetDeferral();

    try
    {
        var fileToShare = await this.GetImageFileAsync("Sample.jpg");
        var storageFileToshare = await this.GetStorageFileForImageAsync("Sample.jpg");

        request.Data.Properties.Thumbnail = RandomAccessStreamReference.CreateFromStream(fileToShare);
        request.Data.SetBitmap(RandomAccessStreamReference.CreateFromStream(fileToShare));

        // On Windows Phone, share StorageFile instead of Bitmaps
        request.Data.SetStorageItems(new List<StorageFile> { storageFileToshare });
    }
    finally
    {
        deferral.Complete();
    }
}

With that code, I’m able to share the image, either as an image or as a file: the OS will choose the available targets according to the format I decided to use.

 

Happy coding!