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

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!

The Binding feature of Xamarin is one of the most powerful one that I’ve seen when playing with the product. Indeed, it allows you to reuse any Java libraries (available as JAR files) directly from your application (written in C#).

This wonderful feature is made available by the Xamarin team thanks to the Managed Callable Wrappers. If you look at my first article about Xamarin, you’ll learn that the MCW are just JNI (Java Native Interface) bridges, some generated code, that are used every time the managed code needs to invoke Java code (on the other hand, when the Java code needs to call managed code, it’s another bridge, named Android Callable Wrapper, that is used).

 

Using the feature is really simple thanks to Visual Studio (or Android Studio). First, you need to create an Android Bindings Library:

image

Once this is done, the IDE will create a project containing the following elements:

  • A folder “Jars” that contains all the JAR files you want to reuse
  • A folder “Transforms” that contains some configuration files used to control the wrappers’ generation
  • A folder “Additions”, that can contains C# code which can be added to the generated classes

image

As we told previously, we’ll be able to reuse any Java library so, for this article, I’ve just grabbed a copy of the Java Image Library available here: http://www.jhlabs.com/ip/filters/download.html

Once you’ve downloaded the JAR file, simply drop it to the Jars folder and set its “Build Action” to “InputJar”:

image

This tells Xamarin to create a bridge for each Jar files defined using this build action.

So now, you’ve basically finished your job. Indeed, most of time, you have nothing else to perform but just compile to get a .NET DLL that can be referenced to your Xamarin.Android application.

If you care, you can take a look to the folder obj\Debug\generated\src to see the generated files used to create the DLL:

image

Sometimes, you might need to solve some issues due to the code generation. Indeed, folks at Xamarin performs 99% of the code generation but there are some things you need to change in order to compile correctly.

In our case, here is the result when we tried to compile our project:

image

Holy crap, it’s not working! According to the error message, it looks like we have a member of a class with the same name as its enclosing type. If we perform a double click on the error message, Visual Studio opens the generated file on the error:

image

Interesting right? We can see that the Histogram class that has been generated has a property named Histogram too, which is not allowed. So we need to find a way to rename this property automatically while performing code generation so the code could compile correctly.

To do this, we need to check in the “Transforms” folder to see the files available for the code generation customization:

  • EnumFields.xml is used to map a Java int value to a .NET enum
  • EnumMethods.xml is used to change the generation of methods’ parameters
  • Metadata.xml is used to change names of types, members, etc.

image

As we want to change the name of a class member, we need to edit the file Metadata.xml to instruct the code generator to change the name of the field Histogram of the type Histogram.

So we just add the following:

<attr path="/api/package[@name='com.jhlabs.image']/class[@name='Histogram']/field[@name='histogram']" name="name">Current</attr>

 

Doing so, we just tell the code generator to change the name of the field Histogram of the type Histogram and to replace it by “Current”. Now, if we build the library, we don’t get any errors and if we look on the generated file, we can see that the property’s name has changed:

image

Now, we can test our library! For that, it’s simple: just create a new Xamarin.Android application and add a reference to your library:

image

Note: If you have some issues when adding the reference as a project reference, try to add it as a DLL instead (see here)

Then, using the library is as simple as using any existing libraries:

image

Even if that works fine, there are at least 2 things that I don’t like:

    • The namespace are the Java’s one
    • The name of the parameters are p0, p1, p2, etc.

Changing the namespace is straightforward. Once again, we need to edit Metadata.xml:

<attr path="/api/package[@name='com.jhlabs.image']" name="managedName">ImageProcessingLibrary</attr>

Thanks to this line, we are able to change the name of the .NET namespace (without touching of the Java’s one):

image => image

Again, as the name of the namespace change, we need to modify the code of our test application:

image

Now, let’s see how to change the name of the parameters. This one is not complex but might take the most of time, as you may want to do it for all the methods.

Again, all will be done in Metadata.xml, by adding the following line (one line for each methods’ parameters you want to rename):

<attr path="/api/package[@name='com.jhlabs.image']/class[@name='LightFilter']/method[@name='addLight']/parameter[@name='p0']" name="name">lightToAdd</attr>
<attr path="/api/package[@name='com.jhlabs.image']/class[@name='LightFilter']/method[@name='removeLight']/parameter[@name='p0']" name="name">lightToRemove</attr>

We just instruct the code generator so in the namespace com.jhlabs.image, find the class LightFilter, look for the methods addLight and removeLigh and rename the parameter initially named p0.

Here is the code that has been generated:

image image

And when using the Intellisense, we can see the correct name for our parameters:

image

 

Previously, I talked about the “Additions” folder which can contains code that will be added to the generated classes.

Using this feature is as simple as writting code files and put them in the folder (all the magic is performed at compilation). All the classes generated by the code generator are marked as partial so it’s easy to add custom code. For example, add a file containing the following code:

public partial class LightFilter
{
    public void AddLightByName(string lightName)
    {
        //
    }
}

Now, if you compile and use your library, you’ll be able to use the new method AddLightByName:

image

 

As you can see, the Binding feature is really cool and easy to use! Of course, most of the job is performed under the cover by the Xamarin tools but it’s very flexible and configurable so let’s try it: you won’t regret it!

If you want to know more (specially about the possible errors you may encountered), you can check the official documentation.

Happy coding! :)

As I’m working on a small ASP.NET MVC 5 application, I wanted to deploy it on Windows Azure to test it. Thanks to Visual Studio, the deployment was really easy but, as soon as I tried to browse the website, I received the following error message:

Could not load file or assembly ‘Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ or one of its dependencies. The system cannot find the file specified.

 image

After searching a bit, it appears that the error is due to the reference Microsoft.Web.Infrastructure.dll that is not deployed automatically with your app. To resolve the issue, just select the reference, go to the properties and set “Copy Local” to true:

image

Once this is done, deploy your website again and now, it should works fine!

 

Happy coding!

I’m proud to announce that my second MSDN article has been finally published in the August issue of MSDN Magazine!

Entitled “Build MVVM Apps with Xamarin and MvvmCross”, the article will let you know all you need to start developping MVVM apps with Xamarin and MvvmCross.

I hope you’ll like it!

 

Happy coding!

[VSX] How to be notified of the debug events ?

July 18th, 2014 | Posted by Tom in .NET | Article | Visual Studio | VSX - (0 Comments) | Read: 572

For an addin I’m workin on, I wanted to present a window to the user but only when Visual Studio is starting a debug session.

For that, I’ve found you can use the IVsDebuggerEvents interface which provides notifications when debugger changes mode.

On the class that need to be notified of the changes, get the current debugger and register for debug events:

uint _debugEventsCookie = VSConstants.VSCOOKIE_NIL;

_debugger = (IVsDebugger)this.GetService(typeof(IVsDebugger));
ErrorHandler.ThrowOnFailure(_debugger.AdviseDebuggerEvents(this, out _debugEventsCookie));

Once this is done, the method IVsDebuggerEvents.OnModeChange will be called so you’ll be able to know when the debugger changes mode:

int IVsDebuggerEvents.OnModeChange(DBGMODE dbgmodeNew)
{
    switch (dbgmodeNew)
    {
        case DBGMODE.DBGMODE_Run:
            // Start Debug Session
            break;
        case DBGMODE.DBGMODE_Break:
            // Break Debug Session
            break;
        case DBGMODE.DBGMODE_Design:
            // Stop Debug Session
            break;
    }

    return VSConstants.S_OK;
}

Of course, don’t forget to perform some cleanup when you’ve finished:

protected override void Dispose(bool disposing)
{
    if (_debugEventsCookie != VSConstants.VSCOOKIE_NIL && _debugger != null)
    {
        ErrorHandler.CallWithCOMConvention(() => _debugger.UnadviseDebuggerEvents(_debugEventsCookie));

        _debugEventsCookie = VSConstants.VSCOOKIE_NIL;
    }

    base.Dispose(disposing);
}

That’s all (so simple isn’t it ? ;-)

 

Happy coding!

Some parts of the latest versions of Visual Studio are developed using MEF (Managed Extensibility Framework), allowing developers to easily create addins  to extend the features of the IDE. On this article, we’ll cover the basics to add custom tooltips to the Visual Studio’s editor.

A tooltip is a small amount of information which appears just under the mouse, when this one is no longer moving:

image

To create a custom tooltip, we first need to create a class that implement IMouseProcessorProvider:

[Export(typeof(IMouseProcessorProvider))]
[TextViewRole(PredefinedTextViewRoles.Document)]
[ContentType("xaml")]
[Name("MyCustomTooltip")]
internal sealed class CustomTooltipHandlerProvider : IMouseProcessorProvider
{
}

Using MEF, we export the type IMouseProcessorProvider so Visual Studio will know that it can loads the content of this file as a plugin.

The ContentType attribute is used to indicate for which type of document the tooltip will be available. There are a lot of default content types but you can easily creates your own if needed. In our case, the plugin will be loaded for the XAML files.

Once this is done, we have to implement the content of the interface so this is the method GetAssociatedProcessor, returning the MouseProcessorBase that will be used to display our tooltip:

[Import]
public IToolTipProviderFactory ToolTipProviderFactory { get; set; }

[Import]
public ITextStructureNavigatorSelectorService NavigatorService { get; set; }

[Import]
internal IClassifierAggregatorService AggregatorService { get; set; }

public IMouseProcessor GetAssociatedProcessor(IWpfTextView view)
{
    return new CustomTooltipMouseProcessor(view, this.ToolTipProviderFactory, this.NavigatorService.GetTextStructureNavigator(view.TextBuffer), this.AggregatorService.GetClassifier(view.TextBuffer));
}

Now, let’s take a look at the CustomTooltipMouseProcessor class that we have to create. It’s a simple class that derives from MouseProcessorBase:

internal class CustomTooltipMouseProcessor : MouseProcessorBase
{
    private readonly IWpfTextView _view;

    private readonly IToolTipProvider _toolTipProvider;
    private readonly ITextStructureNavigator _navigatorService;
    private readonly IClassifier _classifier;

    private readonly ICollection<FontFamily> _systemFonts; 

    private bool IsToolTipShown { get; set; }

    internal CustomTooltipMouseProcessor(IWpfTextView view, IToolTipProviderFactory toolTipProviderFactory, ITextStructureNavigator navigatorService, IClassifier classifier)
    {
        this._view = view;
        this._toolTipProvider = toolTipProviderFactory.GetToolTipProvider(this._view);
        this._navigatorService = navigatorService;
        this._classifier = classifier;

        this._systemFonts = Fonts.SystemFontFamilies;

        this.IsToolTipShown = false;
    }
}

The most important part of this class is the PreProcessMouseMove method, that will handle any mouse move in the editor:

public override void PreprocessMouseMove(MouseEventArgs e)
{
    var colorConverter = new ColorConverter();

    foreach (ITextViewLine viewLine in this._view.TextViewLines)
    {
        // Get the span for each line
        var lineSpan = new SnapshotSpan(viewLine.Start, viewLine.End);

        // Get the classification for each span
        var spans = this._classifier.GetClassificationSpans(lineSpan);
        foreach (var span in spans)
        {
            // If we are on a XAML attribute
            if (span.ClassificationType.Classification == "XAML Attribute Value")
            {
                // Get the attribute value
                var xamlAttributeValue = span.Span.GetText().Replace("\"", "");

                // Check if the attribute's value is a valid color
                if (colorConverter.IsValid(xamlAttributeValue))
                {
                    #region Tooltip management for FontFamily

                    var convertedColor = colorConverter.ConvertFromInvariantString(xamlAttributeValue);
                    if (convertedColor != null)
                    {
                        var xamlColor = (Color)convertedColor;

                        var spanAtMousePosition = Helpers.SpanHelpers.GetSpanAtMousePosition(this._view, this._navigatorService);
                        if (spanAtMousePosition.HasValue)
                        {
                            var textAtMousePosition = spanAtMousePosition.Value.GetText();

                            if (!string.IsNullOrWhiteSpace(textAtMousePosition))
                            {
                                if (xamlAttributeValue.Contains(textAtMousePosition))
                                {
                                    e.Handled = true;

                                    if (!this.IsToolTipShown)
                                    {
                                        this.IsToolTipShown = true;

                                        var copyHexColorHyperlink = new Hyperlink(new Run("Copy"));
                                        copyHexColorHyperlink.Click += (sender, args) =>
                                        {
                                            Clipboard.SetText(xamlColor.ColorToHexString());

                                            this._toolTipProvider.ClearToolTip();
                                        };

                                        this._toolTipProvider.ClearToolTip();
                                        this._toolTipProvider.ShowToolTip(spanAtMousePosition.Value.Snapshot.CreateTrackingSpan(spanAtMousePosition.Value.Span, SpanTrackingMode.EdgeExclusive),
                                            new Border
                                            {
                                                Background = new SolidColorBrush(Colors.LightGray),
                                                Padding = new Thickness(10),
                                                Child = new StackPanel
                                                {
                                                    Orientation = Orientation.Horizontal,
                                                    Children =
                                                    {
                                                        new Rectangle
                                                        {
                                                            Height = 30,
                                                            Width = 30,
                                                            Fill = new SolidColorBrush(xamlColor)
                                                        },
                                                        new TextBlock
                                                        {
                                                            Margin = new Thickness(10, 0, 0, 0),
                                                            Inlines =
                                                            {
                                                                //new Run(xamlAttributeValue),
                                                                //new LineBreak(),
                                                                new Run(xamlColor.ColorToHexString()),
                                                                new Run(" ("),
                                                                copyHexColorHyperlink,
                                                                new Run(")"),
                                                                new LineBreak(),
                                                                new Run(string.Format("{0}", xamlColor.ColorToRgbString())),
                                                            }
                                                        }
                                                    }
                                                }
                                            }, PopupStyles.PositionClosest);
                                    }

                                    return;
                                }
                            }
                        }
                    }

                    #endregion
                }
                // Check if the attribute's value is a valid color
                else if (this._systemFonts.Any(ff => ff.Source == xamlAttributeValue))
                {
                    #region Tooltip management for FontFamily

                    var xamlFontFamily = this._systemFonts.First(ff => ff.Source == xamlAttributeValue);

                    var spanAtMousePosition = Helpers.SpanHelpers.GetSpanAtMousePosition(this._view, this._navigatorService);
                    if (spanAtMousePosition.HasValue)
                    {
                        var textAtMousePosition = spanAtMousePosition.Value.GetText();
                        if (!string.IsNullOrWhiteSpace(textAtMousePosition))
                        {
                            // FontFamily can have whitespace in their name.
                            if (xamlAttributeValue.Contains(textAtMousePosition))
                            {
                                e.Handled = true;

                                if (!this.IsToolTipShown)
                                {
                                    this.IsToolTipShown = true;

                                    this._toolTipProvider.ClearToolTip();
                                    this._toolTipProvider.ShowToolTip(spanAtMousePosition.Value.Snapshot.CreateTrackingSpan(spanAtMousePosition.Value.Span, SpanTrackingMode.EdgeExclusive),
                                        new Border
                                        {
                                            Background = new SolidColorBrush(Colors.LightGray),
                                            Padding = new Thickness(10),
                                            Child = new StackPanel
                                            {
                                                Orientation = Orientation.Vertical,
                                                Children =
                                                {
                                                    new TextBlock
                                                    {
                                                        Inlines =
                                                        {
                                                            new Run{ Text = string.Format("{0} ({1})", xamlFontFamily.FamilyNames[this._view.VisualElement.Language], 10), FontSize = 10, FontFamily = xamlFontFamily },
                                                            new LineBreak(),
                                                            new Run{ Text = string.Format("{0} ({1})", xamlFontFamily.FamilyNames[this._view.VisualElement.Language], 12), FontSize = 12, FontFamily = xamlFontFamily },
                                                            new LineBreak(),
                                                            new Run{ Text = string.Format("{0} ({1})", xamlFontFamily.FamilyNames[this._view.VisualElement.Language], 15), FontSize = 15, FontFamily = xamlFontFamily },
                                                            new LineBreak(),
                                                            new Run{ Text = string.Format("{0} ({1})", xamlFontFamily.FamilyNames[this._view.VisualElement.Language], 18), FontSize = 18, FontFamily = xamlFontFamily },
                                                            new LineBreak(),
                                                            new Run{ Text = string.Format("{0} ({1})", xamlFontFamily.FamilyNames[this._view.VisualElement.Language], 20), FontSize = 20, FontFamily = xamlFontFamily },
                                                            new LineBreak(),
                                                            new Run{ Text = string.Format("{0} ({1})", xamlFontFamily.FamilyNames[this._view.VisualElement.Language], 25), FontSize = 25, FontFamily = xamlFontFamily },
                                                        }
                                                    }
                                                }
                                            }
                                        }, PopupStyles.PositionClosest);
                                }

                                return;
                            }
                        }
                    }

                    #endregion
                }
            }
        }
    }

    this._toolTipProvider.ClearToolTip();
    IsToolTipShown = false;
}

This method has a lot of lines of code but, basically, the process is simple:

  1. For each line in the editor, we get the line
  2. We then get the classifications of items on the line
  3. For each classification, we check if we are on a XAML attribute
  4. If yes, we check if this attribute’s value is a color or font family
  5. If yes, we get the text under the mouse
  6. If the text under the mouse is contained by the value of the XAML attribute, we proceed the next part of the code, which displays a custom tooltip using the method ShowToolTip of the ToolTipProvider

Thanks to the use of WPF in the IDE, we can display cool new tooltips (in my case, i’ve coded them but you can easily use UserControls).

When running this code, we can see that Visual Studio will launch and when we are in a XAML document, hovering a color or font display the new tooltip:

image

image

image

Those of you who are using Resharper or Web Essentials may have recognize some of the same features ;)

As you can see, it’s really easy to develop addins for Visual Studio and this can help you to increase your productivity.

 

Happy coding!

When using Xamarin.Forms, you have a lot of differents pages and layouts available to build your applications.

The TabbedPage is a very good one that allows you to navigate betweend children pages, using tabs. Unfortunately, the control does not offer the possibility to know when the current page is changing (or has changed).

So, a possible workaround, when using this base class, is to add an event handler on the PropertyChanged event and watch for the property CurrentPage. Here is a sample demoing that:

public delegate void CurrentPageChangingEventHandler();
public delegate void CurrentPageChangedEventHandler();

public class ExtendedTabbedPage : TabbedPage
{
    public event CurrentPageChangingEventHandler CurrentPageChanging;
    public event CurrentPageChangedEventHandler CurrentPageChanged;

    public ExtendedTabbedPage()
    {
        this.PropertyChanging += this.OnPropertyChanging;
        this.PropertyChanged += this.OnPropertyChanged;
    }

    private void OnPropertyChanging(object sender, PropertyChangingEventArgs e)
    {
        if (e.PropertyName == "CurrentPage")
        {
            this.RaiseCurrentPageChanging();
        }
    }

    private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "CurrentPage")
        {
            this.RaiseCurrentPageChanged();
        }
    }

    private void RaiseCurrentPageChanging()
    {
        var handler = this.CurrentPageChanging;
        if (handler != null)
        {
            handler();
        }
    }

    private void RaiseCurrentPageChanged()
    {
        var handler = this.CurrentPageChanged;
        if (handler != null)
        {
            handler();
        }
    }
}

To use it, you now just have to register for the event CurrentPageChanging or CurrentPageChanged:

public class MainPage : ExtendedTabbedPage
{
    private readonly OrganizerView _organizerView;
    private readonly AttendeeView _attendeeView;

    private readonly ToolbarItem _refreshToolbarItem;

    public MainPage()
    {
        this.Title = "Meeting Organizer";

        this._organizerView = new OrganizerView();
        this._attendeeView = new AttendeeView();

        this.Children.Add(this._organizerView);
        this.Children.Add(this._attendeeView);

        this._refreshToolbarItem = new ToolbarItem("Refresh", "refresh.png", () =>
        {
            //
        });

        this.CurrentPageChanged += OnCurrentPageChanged;
    }

    private void OnCurrentPageChanged()
    {
        if (this.CurrentPage == this._organizerView)
        {
            this.ToolbarItems.Clear();
        }
        else if (this.CurrentPage == this._attendeeView)
        {
            this.ToolbarItems.Add(this._refreshToolbarItem);
        }
    }
}

Simple but useful !

 

Happy coding!