Cross-Platform Desktop .NET UI with Avalonia
Cross-platform .NET is all the rage now. You can do console apps in C# and F#, web with ASP.NET Core, mobile with Xamarin. But can you do desktop UI apps?
Enter Avalonia
.NET Core by itself does not provide any UI framework, and Microsoft does not seem to bother with this. They are mostly trying to appeal to web developers, and this is understandable: web apps are much more popular.
With Mono you could at least use Windows Forms, but Mono is old stuff.
Turns out there is Avalonia UI project, and it is pretty decent!
- WPF-inspired, so existing XAML experience translates easily (though there are some differences)
- Supports .NET Core
- Works on Windows, Linux, macOS, and even Android/iOS with Mono
So I’ve decided to try it out. And to make things interesting, let’s do an old-school DOS demoscene inspired falling snow effect!
Creating the UI
First, install Visual Studio Extension.
Create a project with the installed project template. It is a bit outdated, so we’ll have to change
<TargetFrameworks>netcoreapp1.1;net461</TargetFrameworks>
to <TargetFramework>netcoreapp2.0</TargetFramework>
in the csproj file.
We are presented with regular WPF files: App.xaml
, MainWindow.xaml
, and their code-behind.
XAML Designer did not work for me, but who uses it, anyway?
On the screenshot above you can see the animation itself and some controls: button, sliders, and a ListBox
for colors.
Everything is pretty standard, ItemsControl
with DataTemplate
works as you would expect, I did not encounter any difficulties.
MVVM and bindings are also very similar to WPF. I’ve encountered a bug with two-way Slider value binding and had to switch to the nightly build.
Snow Rendering
In XAML there is an <Image Source="{Binding Bitmap}" />
, and SnowViewModel.Bitmap
is a
WriteableBitmap
, a concept well-known from WPF. You can even write to it from any thread, which simplifies rendering.
InvalidateVisual
has to be called on the Image
control in order to refresh the contents after
underlying WriteableBitmap
has been updated.
Drawing is achieved like this:
using (var buf = Bitmap.Lock())
{
var ptr = (uint*) buf.Address;
*ptr = 255; // Change top-left pixel.
}
How to Run?
Tested on Windows, Linux, and macOS:
- Install .NET Core SDK
git clone https://github.com/ptupitsyn/let-it-snow.git
cd let-it-snow/AvaloniaCoreSnow
dotnet run
Conclusion
Even though Avalonia is still in alpha, it worked pretty well for me right away, and with prior WPF experience I could easily achieve the desired result. Impressive!
Alternatives?
- Qt (a bit more complicated)
- Java (lacks pointers)
- Electron (oh god)
UI in this demo is quite simple, but it uses a number of essential features:
- Layout (Grid, StackPanel)
- Bindings, MVVM
- ItemsControl
- WriteableBitmap
This is already enough to build an UI of any complexity.
- Source code: https://github.com/ptupitsyn/let-it-snow
- This article in Russian: Кроссплатформенная новогодняя демка на .NET Core и Avalonia
- Reddit comments: https://www.reddit.com/r/programming/comments/7r1yz9/crossplatform_desktop_ui_with_net_core_and/