Avalonia First Impressions

I’ve documented the first forays into doing cross-platform .NET development with Avalonia . I’ve stated that I’m overall impressed. However what are my deeper thoughts on it?

NOTE This article is from 2019 and Avalonia has been under active development and improvement since that time. Please consult newer tutorials and documentation for how to use this against current releases of Avalonia.

First and foremost I am excited. I’ve written previously about my attempts to be a Linux-based .NET developer across a range of topics . The first of this was in 2016 when I experimented with .NET Linux only to be disappointed in it’s 2nd class status . However back then I was trying to do back-end services sort of work which .NET Core is actualy pretty targeted for. In 2017 I started looking again, as I did in 2018 and each time since, especially with eyes towards desktop apps the experience was looking not up to par. So now I sit here today once again wanting to do cross platform desktop app development and once again looking at whether I’m going to do it in C++ (Qt), Java/Kotlin (JavaFX), .NET (Avalonia or Eto.Forms), or maybe even Flutter. I’ve dabbled with all but for some reason this time it is the draw of .NET that is driving me and between all of the options Avalonia seems to be the most promising. So hats off to the Avalonia developers for getting the product to the point it is at now.

I would imagine all Avalonia developers are interested in cross-platform deployment but I’m not sure how many are interested in non-Windows development. If they were interested in .NET developing on Windows they could just use Visual Studio and WPF. If they were interested in doing .NET development on Mac they could use all of the Xamarin tools now packaged as Visual Studio for Mac. It was always Linux that seemed to be the bastard child of the bunch. You know why? On its best day the Linux desktop is less than 2% of the desktop market. It’s not a target rich place. I’m therefore not surprised at how poorly MonoDevelop worked compared to Xamarin Studio or Visual Studio. For things like web services and straight .NET Core work Visual Studio code does a pretty good job. There is also JetBrain’s Rider which is what I’ve been using since getting back to this. I actually know people who develop on Windows who prefer Rider to Visual Studio. I don’t blame them. Visual Studio has turned into a bloated hot mess. However developing desktop applications on Linux for .NET to run everywhere has been a near impossibility. I never could get Eto.Forms working for me correctly. My Avalonia experience is the first time I was able to pretty much out of the box fire up development and have it “just work”. So again, hats off and I’m very excited.

However the reality is that there are still some issues that will have to be worked through over time. The development team seems very responsive to the community and very open in their development. I really like that in an open source community. They recognize their rough edges and are candid about things from what I can see so far. Again, I love that in an open source community. They don’t have a large corporation with a huge corporate initiative backing them so there is always going to be the realities of resource constraints on development. I therefore present the hiccups and concern areas in the light of constructive criticism and wanting to help work with them on addressing them and/or smoothing them over.

Importance of XAML IntelliSense

First and foremost is the editing of the XAML outside of Visual Studio on Windows. We take for granted IntelliSense, dynamic compilation telling us when we have a bug as we are coding, et cetera. Sometimes it can be a nuisance, “Yes I’m going to add that method as soon as I’m done typing this line!” While it may feel like a nuisance sometimes it feels like operating without the benefit of sight without it. There are ways to address this by looking at code samples, reading the code documentation, trial end error, etc.. You know, it’s doing things the way we did things before the early 2000s. However it feels so slow and cumbersome in the modern era. It’s not impossible. There are people who still insist on not using IDEs to this day, but I’m not one of them. I want all my favorite development toys. Unfortunately right now those don’t exist for Avalonia on Linux. Visual Studio Code seems to have some plugins for it but I keep getting suggestions for WPF not Avalonia. Rider’s XAML system doesn’t work for Avalonia either although I’ve seen some Twitter posts by community members showing something that looks like some people are working on it. There is a project called AvalonStudio which could fit a lot of the bill but it’s currently in heavy beta from what I can tell, which may be able to be a good stop gap for now versus a permament solution. Does it matter anyway? Couldn’t we just be like the VIM/Emacs people?

To some extent lack of IntelliSense and autocorrect in the Avalonia XAML is more of a nuiscance but it’s one that one needs to be aware of. Even in this small tutorial project it bit me in the butt a bit. Take for example this XAML for the AddItemView control:

<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="Todo.Views.AddItemView">
  <DockPanel>
      <Button DockPanel.Dock="Bottom" Command="{Binding Cancel}">Cancel</Button>
      <Button DockPanel.Dock="Bottom" Command="{Binding Ok}">OK</Button>
      <TextBox AcceptsReturn="True"
               Text="{Binding Description}"
               Watermark="Enter your TODO" />
  </DockPanel>
</UserControl>

That code is pretty readable even if you’ve never touched Avalonia. I have two buttons (Ok and Cancel) and a TextBox for entering text. It looks pretty straightforward however in the development of it I had two silent errors when first coding these things. The first has to do with the auto-generated header. The boiler-plate around the UserControl settings at the top came from the dotnet new command which generates the corresponding XAML and C# file. You need to have the right namespace, which for this example is the Todo.Views. As discussed in my write up presently the command line tool generates with a default namespace of AvaloniaAppTemplate.Namespace both in the XAML and C# file (In the end it turns out that this was because the tutorial didn’t include the --namespace argument when invoking the command but that’s an easy one to potentially miss or get wrong. Now if you were aware of that, as I was by the time I got to this, you’ll know to correct for that). The IntelliSense in the C# file editor will flag it right away but in the XAML file it will stay there silently until runtime when the whole thing just stops working. Essentially without the proper namespace it doesn’t know how to find the View for the View Model. When creating new code it should pop out easily but as we are hand-writing additional controls and classes all over this sort of silent error will be harder to diagnose. A more insideous one came from the following (my original code):

<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="Todo.Views.AddItemView">
  <DockPanel>
      <Button DockPanel.Dock="Bottom" Command="{Binding Cancel}">Cancel</Button>
      <Button DockPanel.Dock="Bottom" Command="{Binding Ok}">OK</Button>
      <TextBox AcceptsReturns="True"
               Text="{Binding Description}"
               Watermark="Enter your TODO" />
  </DockPanel>
</UserControl>

I stared at this code for awhile trying to figure out why when I hit the “Add an item” button nothing happened. I had first suspected another namespace issue but no that wasn’t it. I then suspected my action binding was causing the problem. Eventually I gave up and ran the wohle thing in debug mode to track down where things were going awry. Look at the code again. Do you see it? I had a typo on one of the TextBox properties. AcceptsReturns isn’t the right name for that property AcceptsReturn. When the runtime tries to assign this property it can’t find it and the whole event handling for that button click drops out.

Both of these are examples of things that would either be avoided or flagged with IntelliSense like you get with WPF or other editors. While it would be great to have graphical editors like you have in Visual Studio I know that that is quite a ways off in terms of effort. However getting IntelliSense working by branching off/building off of the existing XAML parsers available in JetBrain’s suite could make a a huge difference in cutting down time diagnosing these sorts of issues. Again, perhaps even in beta the AvalonStudio option could be the best way to handle that. You have to build it yourself but it has all of the IntelliSense and even graphical previews. So maybe a Rider/AvalonStudio combo will become my workflow. TBD.

In IDE component building

Again, I’m an IDE person. I could get by with Visual Studio Code for many things but in the end I like having my toys. Another good thing to add to Rider would be the ability to add Avalonia controls/components via the New menu or the context menu in the project browser. I’ve seen plenty of examples of these for other code bases so I know it is possible. Right now the work around isn’t terrible. Essentially I build up folder structures as I need to and then execute the dotnet command directly in the command line window within Rider. However because that part is so easy it leads me to believe that having a JetBrains plugin that does that wouldn’t be too hard either. It may also allow Avalonia to get over the namespace specification problem as well as a post processing step since I’m not sure it’s something they can address directly through the dotnet templating system (but I haven’t looked into it so that is a total WAG).

This sort of capability is already in AvalonStudio. I mention it again for completeness. Why not just use AvalonStudio? Maybe over time it will mature into something that could be my main project. I was actually pretty impressed with how many features it already has. I may even try a stint of using it as the primary IDE, but that will take more study as well. Even if this exists it seems like the Rider community is much larger so having plugins for that would still be advantageous.

Cross-platform differences

There are two ends of the spectrum with respect to the look and feel of cross platform frameworks. The one end says that the cross platform framework should render exactly like a native app would on the same platform. The other end says that the app shouldn’t try to emulate the platform in any way and do their own thing. There are lots of problems with writing cross-platform and then insisting on it look identical to the native interface. The sizes of controls, the fonts and how much the text take up, etc. are radically different between the various operating systems to say nothing for mobile devices. When I’ve seen this “cross platfrom but native” thing it’s often a case of back end code reuse but complete duplication of every nuance of the user interface. That is one way to do it but with the popularity of Electron apps and the growing pervasiveness of our apps being in the browser we see that this isn’t the only “proper” solution.

Avalonia attemps instead for consistency across the platforms. In this [2018 NET Summit presentation](https://www.youtube.com/watch?v=DLHhZJkSqWk , Avalonia developer Nikita Tsukanov went into a lot of details about how the system works, it’s architecture, etc. It’s worth checking out on its own. However the part I want to zero in on is their design goals of the project video at 16:25 in ):

Avalonia Design Goals

Avalonia Design Goals/Philosophy

I really like this list. A Lot. They are making tremendous progress towards it. You can also see they are very much not going for the native rendering concept but instead “unified pixel-perfect rendering everywhere” instead. In the dialog Nikita is a bit more nuanced about it. Having pure pixel-perfect rendering is extremely difficult to impossible. However the important thing if for practical purposes Avalonia is producing the same visual experience. I obviously don’t have a ton of experience with this yet but so far it looks very promising but it has some small subtle differences which may create problems in certain circumstances. Take our basic To Do App again rendered on both Linux Mint MATE and Windows 10:

Avalonia ToDo On Linux

To Do App Running on Linux Mint MATE

Avalonia ToDo On Windows

To Do App Running on Windows 10

If you looked at them completely separate from each other they look identical. When they are right next to each other however you can see some subtle differences in the fonts. Maybe there are some subtle differences elsewhere too. To determine the differences definitively I took the screen captures and put them in GIMP to overlap them on top of each other. This is what you get when you look at them overlapping:

Avalonia Linux VS Windows Comparison

Overlay of Linux and Windows panels show pretty good consistency.

As we can see the controls line up beautifully. The fonts are pretty close too however there is a difference in the character spacing/kerning between them. This creates the most dramatic difference in the button where the centering of the text area shifts things a lot more. Is this problem addressable in theming? I would bet that it is. The place where this could cause problem is in a tight UI space where on one platform the text wants to overflow and on another it doesn’t. Overall though these presentations are pretty darn spot on. They are far closer than you’d get with native controls, which again would probably require individual platform implementations. I’d want to study more about what one has available to address some of this but from a practical perspective I think they are nailing this.

More documentation and Tutorials

I’ve been pretty pleased with the onboarding process for Avalonia compared to other systems. They even have a tutorial that worked mostly out of the box on Linux! Like any software project it can always use with more documentation and more examples and tutorials though. For example I fumbled around figuring out how to do the deployment to get proper dependencies. I actually still haven’t nailed that down all the way. A lot of the API documentation is full of TODO place holders. When I asked about it on their Gitter forum it was due to resource constraints, which is totally understandable. What one is left with then without IntelliSense and without Documentation is to look through the Unit Tests or other areas where the code could be used. That’s a lot more detective work than a casual user would be willing to do but for someone who needs to at least the possibilty if being able to figure it out is there. Worst case the responsivenes of the development team and the community at large has been at or better than what I’ve seen for some commercial products. If anything I’d be worried that they may get too distracted from it, but the pace of development doesn’t show that at this time.

Conclusion

So as I’ve said several times in several posts before I’m entering using this product with a very positive perception of them. The product looks solid. The product is in active development. The developers seem motivated and engaged both with the other community developers and the users of the software. There is good documentation and tutorials to start onboarding. The product looks solid enough to build real products with it even though there are still tons of new features and capabilities going in every day. There is even a pretty full feature actively developed Avalonia IDE being written with Avalonia itself. Best still is that it is practical for me to be a Linux .NET desktop application developer using Avalonia with some combination of Visual Studio Code, Rider, and AvalonStudio.

I’ve said several times they need more developer resources. As this is a project that seems to be hitting my sweet spot I’m looking forward to contributing towards it. I need to learn how to use the library so helping fill out the documentation is a great way to learn more about it. I have some small personal software projects I want to work on so I’ll be doing that while also working on fleshing out documentation. I’ve already initiated my first PR against the tutorial to tighten it up with a bit based on my findings of doing this on Linux.

My initial next steps as I see right now are:

  • Write my first real from scratch app using the framework
  • Play around with AvalonStudio to see if it can be a full time Linux .NET IDE for me and/or what combination of that plus Rider/Visual Studio Code is appropriate.
  • Figure out application deployment and packaging so that it could be delivered as a drop-install for Linux, Mac, and Windows
  • Assist with fleshing out the documentation, tutorials, examples, etc. as I write the app. That can take the form of personal blog posts, edits to the main API documentation, etc.
  • Attempt an app that links against native libraries and can still be properly deployed across the three platforms. Yes this seems random but I have a use case for this.

So, I’m off to the races so to speak when it comes to Avalonia. If you haven’t looked at it yet I highly recommend it.