.Net, C#, coding, Design, Material Design, UX, WPF, xaml

Material Design In XAML – 1.5

It’s a big new release for MD in XAML Toolkit! This release focuses on a new transitions API (when I say API, I mean fully usable from XAML), which takes the pain out of WPF storyboard-ing, making animations on individual elements, and between whole “pages” easy.

Release page.

To showcase what can be done I’ve created an entirely new demo app. What’s great is that I was able to build version 1.0 of the demo app in less than a day. All the animations are “out of the box”; straight from Material Design In XAML Toolkit, with zero fiddling with WPF storyboards or animations (but yes, the extensibility is still there!)

It looks a bit like this:

main.gif

You can get your hands on the new demo at it’s new GitHub page.

On top of that there is also a small demo in the main Material Design In XAML Toolkit demo project.

To understand usage of the new transitions API, take a look at both demos and check out the wiki page.

I say this every release, but it’s always true, there have also been some great additions and fixes from the community (which is really growing nicely).  Full release details are here.

I guess with any software library it takes a while to gain traction, but this library is now just over a year old, seems to have plenty of users and I’m seeing some nice looking UIs appear.  With 1.5 I’m hoping for some nice animation flourishes!

Happy UXing!

James

P.S. n00b to Material Design In XAML Toolkit?  Check out the Getting Started guide.

 

Advertisement
.Net, C#, coding, Roslyn

Generate a C# Enum with Rosyln

I’m currently working on an Icon Pack for my Material Design library and need to generate an enum containing a list of all the icons.  Before you delve into this code you should know that the same result could no doubt be achieved using simple string manipulation in a lot less time.  But I took this as an opportunity to learn a little about Roslyn, so if that’s what you’re after then read on.

I set about creating a code template for the enum with the intention of using Roslyn to clear the dummy enum values out and re-populate the enum with a new list.  Sourcing the list of values is the easy part and not discussed here.

To begin with, this is my starting code template:

namespace MaterialDesignThemes.Wpf
{
    /// ******************************************
    /// This code is auto generated. Do not amend.
    /// ******************************************

    /// <summary>
    /// List of available icons for use with <see cref="Icon"/>.
    /// </summary>
    /// <remarks>
    /// All icons sourced from Material Design Icons Font - <see cref="https://materialdesignicons.com/"> - in accordance of 
    /// <see cref="https://github.com/Templarian/MaterialDesign/blob/master/license.txt"/>.
    /// </remarks>;
    public enum IconType
    {
        AutoGeneratedDoNotAmend
    }
}

First lesson.  If you want to do something similar, install the .Net Compiler Platform SDK.  Stupidly I didn’t do this until I had the code 75% complete.  The solution below looks pretty simple but as is oft the way, figuring it out was the hard part.  The Syntax Visualizer Visual Studio add-in included in the SDK would have got me there a lot quicker.

If I had of used the Visualizer in VS 2015 earlier (View > Other Windows > Syntax Visualizer), upon highlighting my above code template I would have seen this, which gives you a pretty good idea of what we’re working with:

SyntaxVisualizer

Second lesson.  The nuget package you are probably after is (took me a bit of digging to get the right one):

Microsoft.CodeAnalysis.CSharp.Workspaces

Also, I found ReSharper’s Hierarchy tool pretty useful to start understanding the class relationships; soon realising that we’re going to be spending a lot of time working with SyntaxNode objects and derivations thereof:

SyntaxNodeHierarchy

One of the first things to learn about Roslyn SyntaxNode objects is that they are immutable.  If you make a change then you’ll get a new one.  Obviously what we want to do is remove our AutoGeneratedDoNotAmend enum value (EnumMemberDeclarationSyntax) from the owning enum (EnumDeclarationSyntax) and replace it with a bunch of new members.  Meaning we’ll end up with a new enum/EnumDeclarationSyntax, in turn meaning we need to swap it out in the parent (NamespaceDeclaration) which again give us a new namespace, so we’ll have to swap that in the root’s children giving us a new root.  Effectively we start at the bottom and replace/renew everything walking up the ancestry of the tree.

Maybe there’s a better way, but this is my first crack at Roslyn and is very much a learning experience.

My first cut of the code (done prior to me installing the Visualizer/SDK, and using some pretend enum values) turned out like this:

private void UpdateEnum(string sourceFile)
{
    var sourceText = SourceText.From(new FileStream(sourceFile, FileMode.Open));
    var syntaxTree = CSharpSyntaxTree.ParseText(sourceText);

    var rootNode = syntaxTree.GetRoot();
    var namespaceDeclarationNode = rootNode.ChildNodes().Single();
    var enumDeclarationSyntaxNode = namespaceDeclarationNode.ChildNodes().OfType&amp;amp;amp;amp;amp;lt;EnumDeclarationSyntax&amp;amp;amp;amp;amp;gt;().Single();            

    var emptyEnumDeclarationSyntaxNode = enumDeclarationSyntaxNode.RemoveNodes(enumDeclarationSyntaxNode.ChildNodes().OfType&amp;amp;amp;amp;amp;lt;EnumMemberDeclarationSyntax&amp;amp;amp;amp;amp;gt;(), SyntaxRemoveOptions.KeepDirectives);
    var generatedEnumDeclarationSyntax = emptyEnumDeclarationSyntaxNode.AddMembers(
        SyntaxFactory.EnumMemberDeclaration("Aston"),
        SyntaxFactory.EnumMemberDeclaration("Villa"));

    var generatedNamespaceDeclarationSyntaxNode = namespaceDeclarationNode.ReplaceNode(enumDeclarationSyntaxNode, generatedEnumDeclarationSyntax);
    var generatedRootNode = rootNode.ReplaceNode(namespaceDeclarationNode, generatedNamespaceDeclarationSyntaxNode);

    Console.WriteLine(generatedRootNode.ToFullString());
}

The end result was pretty good, we retain the namespace declaration, comments, but we’ve lost something in the formatting:

namespace MaterialDesignThemes.Wpf
{
    /// ******************************************
    /// This code is auto generated. Do not amend.
    /// ******************************************

    /// <summary>
    /// List of available icons for use with <see cref="Icon"/>.
    /// </summary>
    /// <remarks>
    /// All icons sourced from Material Design Icons Font - <see cref="https://materialdesignicons.com/"> - in accordance of
    /// <see cref="https://github.com/Templarian/MaterialDesign/blob/master/license.txt"/>.
    /// </remarks>
    public enum IconType
    {
Aston,Villa    }
}

More digging and I learn how to create my enum member with “trivia” consisting of leading white space:

var leadingTriviaList = SyntaxTriviaList.Create(SyntaxFactory.Whitespace("        "));
var generatedEnumDeclarationSyntax = emptyEnumDeclarationSyntaxNode.AddMembers(
    SyntaxFactory.EnumMemberDeclaration(SyntaxFactory.Identifier(leadingTriviaList, "Aston", SyntaxTriviaList.Empty)),
    SyntaxFactory.EnumMemberDeclaration(SyntaxFactory.Identifier(leadingTriviaList, "Villa", SyntaxTriviaList.Empty)));               

Current result:

public enum IconType
{
    Aston,        Villa    }

This is good, but I now realised I needed to add a line feed, but to do this I needed the sibling “CommaToken” node to have the correct trailing trivia. I discovered this by tweaking my initial template to include two enum values and taking a look at the Syntax Visualizer:

SyntaxEnumComma

Yikes. This is starting to give me a headache.

Remembering that these toys we are playing with are immutable, I concocted a new method to pull all the comma tokens, and replace with new comma tokens with trailing line feed trivia:

. . .
generatedEnumDeclarationSyntax = AddLineFeedsToCommas(generatedEnumDeclarationSyntax);
. . .

private static EnumDeclarationSyntax AddLineFeedsToCommas(EnumDeclarationSyntax enumDeclarationSyntax)
{
    var none = new SyntaxToken();
    var trailingTriviaList = SyntaxTriviaList.Create(SyntaxFactory.ElasticCarriageReturnLineFeed);

    Func<EnumDeclarationSyntax, SyntaxToken> next = enumSyntax => enumSyntax.ChildNodesAndTokens()
        .Where(nodeOrToken => nodeOrToken.IsToken)
        .Select(nodeOrToken => nodeOrToken.AsToken())
        .FirstOrDefault(
            token =>
                token.Value.Equals(",") &&
                (!token.HasTrailingTrivia || !token.TrailingTrivia.Any(SyntaxKind.EndOfLineTrivia)));

    SyntaxToken current;
    while ((current = next(enumDeclarationSyntax)) != none)
    {
        enumDeclarationSyntax = enumDeclarationSyntax.ReplaceToken(current,
            SyntaxFactory.Identifier(SyntaxTriviaList.Empty, ",", trailingTriviaList)
            );
    }

    return enumDeclarationSyntax;
}

Our result now is looking much better:

namespace MaterialDesignThemes.Wpf
{
    /// ******************************************
    /// This code is auto generated. Do not amend.
    /// ******************************************

    /// <summary>;
    /// List of available icons for use with <see cref="Icon">.
    /// </summary>
    /// <remarks>
    /// All icons sourced from Material Design Icons Font - <see cref="https://materialdesignicons.com/"/> - in accordance of
    /// <see cref="https://github.com/Templarian/MaterialDesign/blob/master/license.txt"/>.
    /// </remarks>
    public enum IconType
    {
        Aston,
        Villa    }
}

There’s just that last curly bracket which needs knocking down a line, but I guess I’ll just have to get back to that…

C#, coding, development, threading, visual studio

Resolving A Dead Lock Is Your Number 1 Priority.

If your app deadlocks during development you might not want the added distraction. Surely you’ve got some feature which you need to get finished off in a hurry that your boss is pressurising you for. Maybe the screen deadlocking is something your colleague is working on, so you can just let them know and get back to the job at hand.

No.

You now know there’s a deadlock. Some deadlocks manifest readily. But others are a rare breed that only happen under rare circumstances, and perhaps even rarer on your CPU compared to those that you will deploy to. If you ignore this deadlock, it’s on your head.

The reality is: you just got lucky. Your team got lucky. You can resolve this problem here and now, without it escaping into the wild.

Stop what you are doing, forget what your boss wants you to do, or whatever task you think you need to do, and investigate the deadlock and knock the problem on the head.

Often I have heard developers say something like, “yeah, it deadlocks there sometimes”. Or worse, “yeah that’s the so-and-so’s code”. But they don’t stop to investigate. They just assume it’s someone-else’s responsibility

It can take time to resolve a deadlock. Sometimes they are pretty easy, but sometimes they can be complex beasts which take time to understand. Threaded code is more often tricky than not, and problems can be oh-so-subtle. But don’t shun it. Be a hero. Solve it.

Whenever I get a deadlock I immediately cease what I am doing. I pause Visual Studio (being my typical dev tool of choice) and put everything to one side. I won’t close the debug session until I am done. Is it half-five and I’ve got to pick the kids up? No problem. Visual Studio occasionally crashes during debug sessions but I have never had a problem when it is left paused. I’ll just leave it overnight, and come back to it with a fresh head in the morning.

I get the Call Stack up, get the Threads window open and sit there – sometimes just staring for long periods – and try and work through what’s happening. Often in large systems I’ll be working through vast swathes of code I’ve never seen before. There might be multiple context switches, some red-herrings, some code that is down-right ugly. Compiled libraries that you have to break open Refelector/dotPeek or browse Git source to understand. It can be hard, and it can take time: I’ve sat there for hours at a time trying to get things straight in my head, scratching notes on paper, perhaps even firing up another instance of Visual Studio to run through scenarios.

Maybe I’ll take a break, get a drink, some fresh air; but I won’t leave that debug session until I understand what’s causing the deadlock and how I’m going to go about fixing it.