This article introduces Avalonia as a new multiplatform XAML/C# solution for Web and Mobile development platform on top of its Desktop capabilities that have been available for a while. Various API and Visual features of Avalonia are compared to its competitor frameworks and Avalonia is shown to be more powerful and more uniform across multiple platforms than its competitors.
Disclaimer
In this article, I present only my personal point of view.
Avalonia 11 - New Powerful Multiplatform Package
In recent years, software application companies came under pressure from their customers to provide not only Desktop but also Web and Mobile solutions containing most or all of the desktop functionality. On top of that, to increase your customer base, it is always good to create your Desktop applications for multiple client platforms, the main of which are Windows, Mac and Linux.
Before Avalonia 11 was released this summer - the only multiplatform player providing (to different degrees of maturity - depending on the platform) Desktop (Windows, Mac and Linux), Web (WASM) and Mobile (Android, iOS and Tizen) solutions was Uno Platform.
Microsoft's MAUI - does not give the users ability to create very important Web and Desktop Linux applications. Besides I heard that MAUI Desktop functionality is not stable enough for production applications.
Among the current competing platforms (essentially Avalonia, Uno and to a smaller degree - MAUI) - Avalonia is the most powerful and most uniform across multiple platforms as I show below, in this article.
Who is this Article for?
For decision makers, product and project managers, architects and developers.
The article contains a lot of XAML/C# code samples, but they can all be skipped by those not familiar with the code.
Why Multiplatform?
Many companies are now under pressure to provide a UI solution for multiple platforms including Windows, Linux and MacOS. In several of my recent contracts, it was Windows and Linux and in one - Windows and MacOS.
Also, there is an increasing demand for porting the solution to the Web providing most (though not necessarily all) features of the product.
And of course, it is always good to provide Mobile UI for your product, especially for the workflows that can be performed while a person travels, e.g., on a plane.
Why do we need a Single Framework for Building Solutions for Different Platforms
Why can't we build desktop solution for Windows in WPF, for Linux in GTK, for Web in HTML/JavaScript?
The answer is pretty obvious - it will take a much bigger effort to create, maintain and extend any application built with completely different frameworks technologies, while using a single framework the company can re-use a lot of code and developer expertise for all their products at once.
Why XAML/C#?
Many companies have a lot of WPF or Silverlight code which will be much easier to port to XAML/C# frameworks rather than to HTML/JavaScript.
The programming paradigms XAML/C# offers are much more powerful than those of HTML/JavaScript. XAML/C# code is easier to develop, debug and maintain.
XAML can also be used with C++ (e.g. QT framework) but C++ has a very slow compilation time which slows down the development, debugging and maintenance cycles. Most architects and developers agree that one can build an application much faster with C# or Java than with C++. Since Java does not offer a good and flexible UI solution - the UIs built in Java look pretty much the same as old metallic UNIX UIs, so C# is the main option.
Multiplatform XAML Frameworks Discussed in this Article
All the frameworks I compare here are XAML based multiplatform solutions.
- Avalonia - recent version works for Desktop (Windows, Linux and MacOS), Web (via WASM) and mobile (Android, iOS and Tizen)
- Uno Platform WinUI implementation works for Desktop (Windows, Linux and MacOS), Web (via WASM) and mobile (Android, iOS and Tizen)
- MAUI WinUI implementation works for Desktop (Windows and MacOS) and mobile (Android, iOS and Tizen) - does NOT work for Web or Linux
From the above table, you can see the first shortcoming of MAUI in comparison to Avalonia and Uno - it does not allow the products to run on the Web and it does not provide a Desktop solution for Linux.
My Attitude towards Microsoft
In this article, I will say some harsh words about recent Microsoft UI Packages, so I want to clarify that I do not have any major ideological difference with Microsoft a la Richard Stallman. I simply judge various packages as someone who uses them to build products.
Aside from their CURRENT UI division, I actually admire Microsoft as the company which developed and then shared C# - the software development language I consider the best, the most powerful and the fastest developing among software languages. Moreover, they made most of C# (not including the UI) run on multiple platforms including Linux and Mac and opened up its source code under the least restrictive MIT license.
Microsoft also spearheaded development of various programming paradigms, e.g., LINQ, Tasks (Promises) and Reactive Extensions and incorporated them into C# before they were incorporated into other languages.
Microsoft created the best for its time Windows development framework - WPF and came up with multiple UI development concepts including the MVVM pattern - the best pattern for the UI development.
Microsoft has created the best Web Development framework - ASP.NET and continuously working on improving it.
Microsoft has created a strongly typed version of JavaScript - TypeScript which I'd recommend to anyone over JavaScript if they choose HTML/JavaScript as their development platform - the larger the HTML/JavaScript development team, the more need there is for TypeScript.
Microsoft has created WSL - Window Subsystem for Linux making it a breeze to develop and debug Linux UI and console applications on Windows.
On top of that, Microsoft is currently in the forefront in many areas including their Cloud service (Azure), Artificial Intelligence, Embedded Systems and many others.
My Background and Relationship to Avalonia, Uno and MAUI
I am one of the top WPF/MVVM architects and developers.
A couple of years ago, I discovered Avalonia and it was love from the first sight.
In this article, I'll be saying a lot of good words about Avalonia and less so of other frameworks, so I'd like to underscore that I have no connection to Avalonia aside from
- Falling in love with Avalonia from the first sight
- Building several open source Avalonia based libraries
- Writing a number of articles on Avalonia on CodeProject
- Helping them with documentation a couple of years ago and receiving a total of $2500 for it (also a couple of years ago)
- Using Avalonia desktop solutions for a couple of my contracts over a 2 year period of time.
- Now, at the end of 2023 - long time after the article was initially published, I've become an Avalonia MVP
Avalonia is NOT sponsoring me and they were NOT aware of my writing this article before it was published.
Uno Platform
In one of my contracts, I'd been using Uno Platform extensively for about 6 months building some complex controls with it including a Gantt Chart control and the one that imitates and provides a good chunk of Excel Spreadsheets functionality. I was also developing and maintaining a complex mature Uno Platform based application which was a port of an older WPF application.
In my work with Uno, I concentrated primarily on the Desktop and the Web platforms.
MAUI
I never used MAUI for any of my contracts, only played with it including while I was writing this article.
Can the Content of this Article be Trusted?
I think - Yes, because almost everything I state is supported by concrete samples and in spite of my professed love for Avalonia, I am trying to stay as objective as possible.
Sometimes, I'll be using conjectures but in such cases - I'll specifically state that it is only my guess.
The Main Conclusion of the Article
Avalonia, Uno and MAUI can be worked with and I saw products created with Avalonia and Uno platform myself. As for MAUI - it being a next version of Xamarin - I also knew many mobile products created with Xamarin.
Avalonia is a better multiplatform development package than Uno or MAUI.
Now what I mean by "better" - it allows considerably faster development, maintenance and support of the products. In particular:
- It is a more powerful UI package allowing much more re-use and creating shorter code faster to achieve the same functionality. Part of the reason for that is that it is not confined to WinUI/UWP bounds - it is actually more powerful than WPF which is in turn better than WinUI or UWP. Another reason is that it has a better implementation with a lot of code re-usable across all of the platforms while Uno and MAUI essentially have completely different implementations for each of their platforms.
- There are many features in Avalonia that are not implemented in Uno or MAUI, while I do not know a single feature implemented for Uno or MAUI that would not work in Avalonia. If someone knows a single feature available in Uno or MAUI but not available in Avalonia, please mention it in the comments and I will refer to it in this article.
- Avalonia covers all the same platforms as Uno and more than MAUI does and has considerably fewer differences between behaviors on various platforms.
- Avalonia is easier to switch to for an expert WPF developer than to Uno or to MAUI.
The rest of the article just serves to prove the above points.
Comparing XAML/C# Frameworks' Architectures
Avalonia has two advantages over UNO Platform and MAUI:
- Avalonia does not limit itself to WinUI/UWP functionality - in fact Avalonia, in many ways, is considerably more powerful than WPF - it is Multiplatform WPF++, while WinUI (and UWP) API is a pale imitation of WPF API (WPF--). I'll speak more about it below, detailing some of the API that WinUI lacks and providing concrete examples.
- Avalonia's design philosophy was to re-use as much code as possible for different platforms. They built their framework on top of Skia - which is a great low level multiplatform framework. Whatever they could not use Skia for, they achieved by the platform specific solutions. UNO and MAUI's philosophy was the exact opposite - they used as much of the native code as they could for each of the platforms and their implementations are completely different for each of the platforms they cover as they try to use as much native platform functionality as possible.
Here is an Avalonia Architecture diagram.
Polyfill is a common API (interfaces) with platform dependent implementation. As you see, the platform specific code takes only a small fraction of total Avalonia code while most of the code is the same for each one of the platforms.
Here is an Architecture Diagram for Uno Platform:
Every implementation has completely different code - in fact, the Web implementation generates the HTML while Windows implementation uses WinUI native calls; Linux - Skia and Mobile and MacOS implementations are using Xamarin. As a result, Uno is forced to maintain essentially 4 different versions of its code and the available features and behaviors are different on different platforms - I know it all too well and will talk more about it below.
And here is MAUI Architecture Diagram:
MAUI covers fewer platforms but suffers from all the same drawbacks as Uno:
- It tries to implement WinUI (which is WPF--)
- It uses as much native code as it can - so that each platform essentially has its own implementation.
WASM Playgrounds
Both Avalonia and Uno have Web (WASM) playgrounds which you can check - Avalonia Playground and Uno Playground
MAUI does not have a Web playground (since there is no MAUI Web solution).
WPF
About 20 years ago, a group of very bright people with much experience in UI development at Microsoft came up with a great new .NET package for desktop development on Windows. The project initially was called Avalon and then was given name WPF (Windows Presentation Foundation).
Why was WPF great? Because:
- Its low level features allowed creating and customizing almost any UI on Windows exactly to match the client's requirements.
- It came with a lot of high level features representing newly discovered and formalized UI concepts that made it possible to achieve great separation of concerns and re-use. In particular:
- WPF took the concept of Composition to a new level - almost any simple control can be assembled from basic primitives like borders, panels, shapes, images and texts.
- Visual and Logical trees reflecting the composition hierarchy of the WPF UI controls.
- Dependency and Attached properties for saving memory and allowing to attach a value to a new property on a WPF UI element without modifying the class of the element.
- Bindings allowing to bind a target property to a source property. Almost every property on the WPF UI element is bindable. Bindings together with
DataTemplates
eventually resulted in MVVM pattern allowing full separation between visual and non-visual code in such a way that non-visual code contains most of the complexities while the visual code passively mimics the non-visual code. - Routed Events (which also can be Attached Routed Events) that propagate up and down the visual trees. E.g., a contained element can fire such event, but it will be handled on the containing element.
- Control Templates - allowing re-using parts of XAML.
- DataTemplates - allowing converting some non-visual data into a visual.
- Styles - allowing to easily restyle WPF controls. Styles can also be inherited from other styles.
- Template and Style Triggers allowing to modify the behaviors easily.
- It allowed using some low level graphics mechanisms for building faster controls.
It also contains many other less important concepts and improvements that I omit here. - WPF has great integration with MS Visual Studio (XAML intellisense and the Designer) and the best open source Spy tool called Snoop.
A lot of bright people figured out WPF potential, immediately jumped on WPF bandwagon and created an internet society called WPF Disciples. I can name Karl Schifflett, Josh Smith, Peter O'Hanlon, Sacha Barber, Beatrix Costa, Rob Eisenberg. There were also many others whose names I do not remember at this point.
After Microsoft abandoned Silverlight and put WPF on the back burner providing instead pitiful surrogates (UWP and WinUI), many of these people switched to other (non-Microsoft) technologies.
Now, think about the name of the internet society - WPF Disciples. The people who created this internet society, understood that WPF is much more than another package for Visual Development. They understood that WPF is a new philosophy of development - essentially a new set of very deep and useful paradigms allowing much faster development and creating much leaner code which is easier to maintain and expand. Moreover, many WPF features can be also used in non-Visual development (though I do not think that they are currently being widely used outside of Visual development).
Some people were complaining that WPF is too complex to learn. My answer to that is that WPF is not more difficult than the visual programming. WPF did not have many unneeded features - those that are not required for the good visual programmers to know.
WPF definitely has a learning curve, but once you know and understand WPF, you can code very complex products very fast and lean.
Basically WPF has a certain barrier to entry, but once you know and understand it - you love it and it gives you tremendous development power.
Silverlight (Of Blessed Memory)
WPF had one major drawback - it was not multiplatform. Because of that at some point, a Microsoft department under Scott Guthrie created Silverlight (formerly called WPF everywhere).
Silverlight had many (but not all) WPF features - I was constantly running into some quirks, e.g., the strange limitation that custom attached properties could not be animated and many others. Yet it had a great advantage: it (together with its version of .NET framework - which was not full featured either) could run on multiple platforms.
At first, Silverlight was released as a browser plugin for most of the popular browsers, but later MS also provided a Desktop version.
Troubles in Microsoft UI Programming Paradise - Application Division Attacks
Speaking of the picture above - I do not know which Microsoft division is a villain there and which one is the good guy - I think each one is a little bit of both.
Apparently, there were some tensions between Microsoft's Windows and Application divisions. Windows division was mostly working with C++ and Application division - mostly with C#.
.NET C# experts encouraged by the success of C# and WPF/Silverlight wanted to re-write the whole Microsoft OS in .NET Framework. Whether due to poor cooperation from the Windows division or due to some other reasons, but this effort essentially resulted in MS Vista OS which was not popular at all among the companies and developers.
More Trouble in Microsoft (Windows Division Strikes Back)
Around 2010-2011, Microsoft realized that it was a mistake not to build their own mobile platform. By that time, Apple and Google were far ahead of Microsoft in market capitalization due to their domination in smart phone/tablet market.
Apple was the first to create a mobile platform (at the same time, they locked their operating system). Google came second to the market, but since Google products were cheaper and Google's Android system was open source, eventually Google took more than half of the mobile market share.
While Microsoft correctly identified the problems, it (undoubtedly under the influence from their money making Windows division) came to all wrong conclusions listed below:
- C++ should be the language to write most of the applications in. (C++ has very slow compilation so it is not a good language for application development in comparison with C# or Java).
- HTML5/JavaScript will suffice for multiplatform application development. (Neither TypeScript nor any of the new JavaScript frameworks - Angular, Vue or React - came even close to WPF in power, speed of development, ease of maintenance).
- Therefore Silverlight/WPF and C# should be abandoned or close to abandoned.
- Start Button from which people start their Window applications on their Desktop and Laptop computers should be abandoned (this is a pretty ridiculous one since desktop/laptop and mobile usage cases are completely different and each one should be treated differently and use a different UI).
- Microsoft should work towards closing their system like Apple. (Coming very distant 3rd to the mobile market, they were trying to behave like the market leader).
This attitude actually led to wasting billions of dollars on creating their own mobile platform and hardware - Windows RT that could not run the .NET framework and C#. Windows RT (as a stand alone OS) and Microsoft mobile hardware eventually were buried due to the lack of interest in it, which in turn was caused by:
- the lack of the application development - developers did not like the new platform.
- the OS that was not open source (e.g., like Android) and people were afraid will be closed completely so that only Microsoft will decide which application to allow on it and which not - kind of what Apple did to Silverlight mobile version.
- Lack of confidence in what Microsoft will be doing next.
- Failure of Microsoft 8 OS - which was largely due to the lack of the Start Button and turning tin ear to the customers' complaints.
The Compromise
Eventually, the MS Application developers convinced Microsoft to leave C# and WPF development intact at least for some time and later, the failure of the approach advocated by the Windows division confirmed the validity of C# and .NET so that not only they have not been abandoned, but became multiplatform (working on Windows, Linux, Mac, Embedded Systems and inside the browsers via WASM) and one of the fastest developing and widest used platforms/languages.
Even before it became clear that C++ is not a good language for application development, the fans managed to defend XAML so that the subsequent Windows packages UWP and its more recent replacement WinUI were XAML based.
What are UWP and WinUI
Both UWP and WinUI can be called WPF-- (WPF minus minus - pale imitations of WPF). Both provide wrappers around Windows functionality so that the resulting API is somewhat similar to WPF/Silverlight. However, many very useful features are missing - I'll give more details about the missing features below.
For a WPF developer, switching to UWP or WinUI is equivalent to switching back from a Harley-Davidson Motorcycle to a bicycle. This is why many developers either stayed with WPF or switched to non-Microsoft technologies.
Case in Point: After more than 10 years of Microsoft promoting UWP and several years of promoting WinUI - there is not a single UWP or WinUI job showing on Dice while there are 120 WPF jobs (this is today as I am writing this article - of course, numbers can vary from day to day but they usually stay close).
Obviously, the UI development in Microsoft was put on the back burner - there is no interest in it and the UI team can release one almost-failing product after another without any consequences.
Comes Avalonia
Some developers who loved and understood WPF got together and created a new open source, multiplatform framework called Avalonia. If UWP and WinUI is WPF--, then Avalonia (even aside from its being multiplatform) is WPF++. It has almost all features of WPF and also a number of extra features that make programming Avalonia even more powerful and efficient.
Unlike its competitors, Avalonia tries minimizing the reliance on the native code, instead it uses Skia (the multiplatform framework for low level visual elements).
Until recently, only Avalonia's desktop solutions were stable, now, however Avalonia 11 has been released several weeks ago and it supports Web via WASM and mobile platforms (iOS, Android and Tizen) as well.
Avalonia is completely open source and comes with the most permissive MIT license, meaning that you can use it for both commercial and non-commercial products and you are free to modify the code as long as you mention that the original code was from Avalonia.
Avalonia for Desktop has been thoroughly tested by many products built with Avalonia - listed on Avalonia's website.
Uno Platform
Uno Platform has been developed by Uno company and its purpose is also to provide multiplatform Desktop, Web and Mobile solutions. It is closely connected to Microsoft - several of its founders are Microsoft's MVPs. Correspondingly, it suffers from the same shortcomings that the Microsoft products are suffering from.
Essentially, Uno Platform provides a WinUI (or older version - UWP) implementation for Windows, Linux, Mac, Web and Mobile platforms.
Also following Xamarin and MAUI example, Uno is implemented as wrappers around the native platform calls. This leads to completely different code, e.g., for Windows, Linux, Mobile and the Web. In fact, while Uno for Windows is implemented as wrappers around Windows native calls, its Web implementation relies on generating the HTML/JavaScript code.
As a result, features that work on the Windows platform might not work the same on the Web. In fact, after making Windows work, one has to switch to the web and make the same feature work on it also. And it might take some time to figure out how to do it. The same is with the bugs: something that works on Windows might crash on the Web and vice versa.
I'll talk more about the concrete cases below.
On the average, when programming Uno, I spend about 6-8 hours a week making the Web version behave similar to the Windows version.
For Avalonia - such time is close to 0.
MAUI
MAUI is a new version of Xamarin with some ability to create desktop applications also. So far, I never saw myself a desktop application being built with MAUI and on some forums the opinion about using it for desktop application was generally negative.
It suffers from the same problems as Uno while covering fewer platforms.
General Description of the Samples
As was stated above, Avalonia is WPF++ while WinUI (which is replacing UWP) is WPF--. Also, because of Avalonia Architecture, it has a considerably better chance that a feature developed for one platform will also work on another.
Also, Avalonia has better development tools and faster compilation time for large projects than either MAUI or Uno Platform.
Correspondingly, the comparisons are divided into the following groups:
- Comparison of the development tools and the debugging capabilities - verbal only without code samples.
- Code samples, proving Avalonia has all the important features missing in WinUI (and correspondingly missing in Uno and MAUI).
Please, note that in order to understand the samples' code, I expect people to have some understanding of XAML/C# frameworks - preferably WPF.
Those who do not know WPF or other XAML/C# packages can skip the code and just read the text.
Comparison of Platforms Covered, Development Tools, 3rd Party Packages and Debugging Capabilities
Open Source
All three frameworks - Avalonia, Uno Platform and MAUI are open source and released under the most permissive MIT license. Meaning that you can essentially do what you want with code and with the packages, use it in any commercial or non-commercial products as long as you mention that the original code was from the corresponding package.
The source code for all three packages is location on Github. Here are the locations:
- Avalonia
- UNO Platform
- MAUI
Platforms Covered
As was mentioned above, Avalonia and Uno Platform cover Windows/Linux/MacOS for Desktop, Web and Android/iOS/Tizen for mobile.
MAUI - does not provide a solution for Linux Desktop or the Web - in a sense, it is in a disadvantage here.
Third Party Controls
Complex Third Party Control
Another important issue - is availability of the third party especially for implementing some complex ideas, e.g., Desktop Docking/Grouping/Tabbing control, MS Excel, Reporting, PDF or Layout Management controls. Neither Avalonia nor Uno nor MAUI have such complex controls built for them aside from my own UniDock Docking/Grouping/Tabbing open source solution for Avalonia which I still need to upgrade to work with Avalonia 11.
Simpler Controls developed by well-known Component Companies
When it comes to simpler controls, the MAUI is in clear advantage because of the Microsoft name behind it - DevEx, Telerik and other major companies are developing controls for MAUI, though at this point, those controls are not as complex as those for WPF and mostly serve the Mobile, not the new MAUI desktop solution. Most of these simple controls provided so far by big names, can be easily created and styled in both Avalonia and Uno.
DataGrid and Tabs Controls
Both Avalonia and UNO Platform have DataGrid
and TabControl
coming either as part of their source code (for Avalonia) or as part of an open source package (for UNO Platform).
MAUI has built-in TabBar
and some commercial solutions for the DataGrid
, e.g., by Telerik or SyncFusion.
Charts
Several charts built on top of Open GL have compatibility (at least for Desktop and Web Avalonia packages). In particular, OxyPlot, LiveCharts and ScottPlot work with Avalonia.
There is also a a commercial solution - Tee Chart.
Telerik and Syncfusion have commercial charting components for MAUI.
Syncfusion also has Uno Chart control - in beta version.
Coming Soon
Actipro Controls for Avalonia.
Product Speed
This is my subjective view that Avalonia products in general are faster across multiple platforms than Uno.
One exception is - the Avalonia DataGrid
control inside the Browser scrolling is as slow as that of the corresponding Uno control (both under AOT compilation).
Both Uno and MAUI are built as wrappers around WinRT native calls on Windows. There are several well known problems with WinRT interop which makes the WinUI Dependency Properties performance very slow. This problem is detailed e.g. in the following link: WinUI 3 Performance Boost.
Also the github issue link: "Dependency property is much slower in WinUI 3 than in WPF" shows that this problem has been known to Microsoft since Nov 2019 and nothing has been done about it.
Spy Tools
WPF Snoop
WPF has a great UI Spy tool - Snoop. It allows:
- Displaying the visual or logical tree
- Finding elements within the visual or logical trees fast
- Checking and modifying the Attached and Dependency properties on an element
- Iteratively delving (drilling down) into properties - allowing to examine the values on the compound properties
- Examining the
DataContext
of an element and iteratively delving into its properties - Viewing the Event propagation - down the visual tree - for tunneling event and up the visual tree for bubbling events. This is very important, e.g., when you want to figure out why some event is not reaching an element on the visual tree.
- Calling
public
methods on any element or public
property.
Neither Avalonia nor UNO, nor MAUI have Spy tools as powerful as WPF. Yet Avalonia has the best Spy tool among the three of them:
Avalonia Spy Tool
Avalonia Spy Tool is considerably less powerful than Snoop (at this point):
It allows:
- Displaying Visual or Logical Trees
- Finding elements within those trees fast
- Checking and modifying the Attached and Dependency Avalonia Properties on elements
- Monitoring the Routed Event propagation up and down the Visual Trees
- Delving (drilling down) into compound properties but not showing info about their bindings
It does not allow:
- To show details about the bindings
- Calling methods on elements and properties
Uno and MAUI
Uno and MAUI allow only using Microsoft Visual Live Tree and Live Properties on it, which is worse than Avalonia Spy Tool since
- It only works when you are debugging your application within Visual Studio.
- It only shows the Visual tree (there is no concept of a logical tree in WinUI).
- It does not allow viewing the routed event propagation.
- It skips some elements especially on complex controls like
DataGrid
. - For some controls, it does not show their properties - I have not figured out any rule there but usually it happens on parts of some complex control, e.g.,
DataGrid
. - Often, it does not allow modifying a property for no valid reason since such property is
public
and settable.
There are two features it provides that are not part of Avalonia Spy Tool:
- Can take instantaneously to the code of an element found within the Live Visual Tree
- Does show information about the bindings
In spite of these extra features, I found it much better to use Avalonia Spy Tool than Live Visual Tree/Live Properties combo and WPF Snoop beats every one of those tools by a good margin.
Visual Studio Version Used for Running the Comparison Samples
I use Visual Studio 2022 17.7 Preview 2.0.
It does not mean that you necessarily need the same version - for most of the samples, the VS 2022 version does not matter.
Avalonia Framework Used for Samples
Avalonia 11.04
Information about the Samples
In general, the samples are divided into two groups - Visual Samples and API samples. Neither is providing an exhaustive list of features available in Avalonia across all the platforms and not available in its competitor frameworks, but I tried to come up with the list of most important and impressing ones.
Introduction to Samples
In order to expand the audience of this article, I will present some sample without discussing much of the code, even though all the code for this article is available and can be found in Avalonia Comparison Samples repository.
All the samples below have been tested on Windows 11, Linux (via WSL), Chrome Web Browser and Android emulator.
In order to run the Desktop samples on Linux - please read my article about it - Running and Debugging Multiplatform .NET GUI and Console Applications on Windows Subsystem for Linux (WSL)
At this point, I do not have ability or time to run the samples on MacOS, iOS and Tizen platforms.
All the samples below run fine in Avalonia but could not be run on Uno Platform or MAUI, either on every or on some particular platforms mentioned in the corresponding samples.
Samples of Visual Avalonia Multiplatform Features not Available in other Frameworks across Multiple Platforms
Blurring a Page Sample
Sometimes, you want to preview some features to the customers without letting the customer use them. One of the adopted practices is to use the Blur effect to allow the customers see some text and buttons without being able to make out whatever is written in them. WinUI has a blur effect so, one can use it on Uno Platform for Windows, but such effect is missing in Uno Web release, since Uno Web is obtained by generating the HTML/JavaScript and the browsers do not have the capability to blur out parts of their HTML tree.
For blurring out the large features, one can use an Acrylic Brush - but it is not suitable for blurring out the small features, e.g., the text and still allowing to see that something is written there.
The code for Avalonia Blur sample is located under NP.Demos.BlurSample
project.
Here are the images of a blurred page for each of the platforms:
Windows Desktop:
Linux Desktop (via WSL):
Blur in Browser:
Android:
Creating and Running Multiplatform Avalonia Projects
This section is only required for people who want to run the samples themselves and/or develop with Avalonia.
In order to create Multiplatform projects with Avalonia 11, you need to install Avalonia Template Studio extension for your Visual Studio 2022:
When creating a new Project, choose "Avalonia C# Project" from Template Studio:
At the next screen, choose the project location and name, then press Create button. Here is what you'll see:
Choose platforms you want your application to run on and press Create button at the bottom.
It will create a re-usable project and several projects to run the application on each of the platforms:
In the BlurSample
Solution, NP.Demos.BlurSample
project is the re-usable one, NP.Demos.BlurSample.Desktop
is to be used for desktop applications (Windows, Linux and MacOS), NP.Demos.BlurSample.Browser
- to run in browser (via WASM) and NP.Demos.BlurSample.Android
- to run in Android or an Android Simulator.
The MainView.axaml and its C# counterpart - MainView.axaml.cs files are for creating the main application. It is going to be used by Desktop, Browser and Mobile applications.
Note that MainWindow.axaml/MainWindows.axaml.cs files are only going to be used by the Desktop applications and will not be used in mobile or browser applications. So the functionality that you want to be accessed from Web and Mobile should not be placed there.
BlurSample Code
BlurSample
code is very simple - the only change is in MainView.axaml file:
<Grid RowDefinitions="*,*">
<Grid.Effect>
<BlurEffect Radius="5"/>
</Grid.Effect>
<TextBlock Text="Welcome to Avalonia"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<Rectangle Width="30"
Height="30"
Fill="Red"
Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
Element to Image Sample
When you build a software application, often you might want to take a snapshot of some part of the screen in order to save it or in order to send it for printing.
Avalonia gives you this ability (in three different ways) on every platform.
Uno gives you this ability with one glaring exception - you cannot turn parts of the screen to image in the Web browser: [WASM] Support for RenderTargetBitmap.
AFAIK MAUI allows screenshots on every platform it covers.
Open and start NP.Demos.ElementToImage
project on the platform you want. Press Render button at the bottom and the top element containing TextBlock
, Rectangle
and Combobox
will be rendered in 3 different rows underneath - two last rows with tiling (though tiling can be turned off).
Here is the resulting images:
Windows:
Linux:
Browser:
Android:
I am not detailing the code here for the sake of brevity, but the only changes were in the files MainView.axaml and MainView.axaml.cs.
The first two rows of the images were achieved with the help of RenderTargetBitmap
converted to a Bitmap
. First Image row displays an Image
control with its Source
property set to the Bitmap
.
Second image row is achieved with a Panel
with its background created by an ImageBrush
.
Third image row represents the easiest way of creating created an image out of control - by the VisualBrush
. Note, that unlike in WPF, the VisualBrush
will not reflect automatically the changes to the control.
Three Dimensional Sample
The code for the next sample I copied from Avalonia source code Render Samples and made it run on different platforms. Please, find it within NP.Demos.Complex3DSample
solution.
Avalonia allows some 3D functionality to be run on multiple platforms with the help of Rotate3DTransform
, which AFAIK neither Uno, nor MAUI allow. Here are the results of running the sample:
Windows:
Linux:
Browser:
Android
Clipping and Opacity Mask Sample
AFAIK, neither Clipping, nor Opacity mask is implemented on Uno Platform (aside from Windows Desktop platform). For MAUI, Clipping is implemented but not the Opacity Mask.
The Clipping/OpacityMask sample is located within NP.Demos.ClippingSample
solution:
Windows:
Linux:
Web Browser:
Android:
LayoutTransformControl Sample
For Uno LayoutTransformControl
from the CommunityToolkit can be used on Windows, but not on the Web (and I am not sure about the mobile).
Avalonia LayoutTransformControl
sample is located within NP.Demos.LayoutTransformControlSample
solution.
First of all, why is it needed.
The sample consists of the view model MainViewModel
that is an ObservableCollection<string>
filled with 1000 sentenses and containing a double notifiable ScaleFactor
property:
public class MainViewModel : ObservableCollection<string>, INotifyPropertyChanged
{
public MainViewModel()
{
for (int i = 0; i < 1000; i++)
{
Add($"This is sentence {i}.");
}
}
#region ScaleFactor Property
private double _scaleFactor = 1d;
public double ScaleFactor
{
get
{
return this._scaleFactor;
}
set
{
if (this._scaleFactor == value)
{
return;
}
this._scaleFactor = value;
this.OnPropertyChanged(new PropertyChangedEventArgs(nameof(ScaleFactor)));
}
}
#endregion ScaleFactor Property
}
The MainView
represents a DataGrid
with a single column each row - corresponding to one of the sentences from the view model and slider at the bottom:
<Grid RowDefinitions="*,40">
<LayoutTransformControl HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
RenderTransformOrigin="0,0">
<DataGrid ItemsSource="{Binding}"
RenderTransformOrigin="0,0">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding}"
Header="Text"/>
</DataGrid.Columns>
</DataGrid>
<LayoutTransformControl.LayoutTransform>
<ScaleTransform ScaleX="{Binding ScaleFactor}"
ScaleY="{Binding ScaleFactor}"/>
</LayoutTransformControl.LayoutTransform>
</LayoutTransformControl>
<Slider Grid.Row="1"
Margin="10,0"
Value="{Binding Path=ScaleFactor, Mode=TwoWay}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Horizontal"
Minimum="1"
Maximum="5"
Width="300"/>
</Grid>
The slider's Value is TwoWay
bound to the ScaleFactor
on the view model and changes from 1
to 5
.
First of all - let me demonstrate why the LayoutTransformControl
is needed, why cannot we do with the RenderTransform
.
Comment out the LayoutTransformControl's
ScaleTransform
and uncomment the similar ScaleTransform
of the DataGrid.RenderTransform
.
Now the layout rule that has to fit the DataGrid
into the allocated space will NOT be observed and the moment you slightly increase the ScaleFactor
by moving the slider - the Scroll Bar on the right will disappear:
Now comment out the RenderTransform
and uncomment the LayoutTransform
of the LayoutTransformControl
- the Layout rules will be observed and both Vertical
and Horizontal
scroll bars will stay where they are supposed to be on every platform involved:
Windows:
Linux:
Browser:
Android:
Low Level Graphics Features Provided by Avalonia
Avalonia, like WPF and Silverlight is providing low level graphics capability via the DrawingContext
of each of its Panels or Controls and this capability works the same across all the platforms covered by Avalonia. Such access can be very helpful for better performance when one needs a fast changing control - e.g., a DataGrid
reflecting Stock buys and sells.
AFAIK neither Uno Platform, nor MAUI are providing such capabilities.
The sample showing such low level capabilities is called NP.Demos.DrawingContextSample
. It simply draws a red circle with a blue border by overriding method Render
of the MainView
control:
public override void Render(DrawingContext context)
{
context
.DrawEllipse
(
Brushes.Red,
_strokePen,
new Avalonia.Point(100, 100),
40,
40);
}
Windows:
Linux:
Web Browser:
Android:
Avalonia API Samples not Available in WinUI (and Correspondingly in Uno Platform or MAUI)
This section might require some understanding of WPF and XAML programming.
In order to avoid showing a lot of code, I'll be using only small code snippets, but most of them are available in NP.Demos.GenericTypesInXaml
and NP.Demos.StaticMarkupExtensionSample
samples.
Here is the list of important APIs missing in WinUI (and correspondingly in either Uno Platform or MAUI):
- Notion of a Logical Tree.
- Binding to a property on an element up the visual or logical trees (
RelativeSource
with AncestorType
mode). CommunityTookit provides a way to do it which works in ~70 to 80% of cases, but sometimes it does not work, unfortunately. For example, I could never bind from a DataGrid
's cell or row to a property on the DataGrid
itself. - Custom Attached and Dependency Properties which can be inherited down the Visual trees.
MultiBinding
- my client implemented it itself, but again there were some cases when it was not working, e.g., two way multibinding. x:Static
markup extension. It is important if one wants to bind, e.g., to a static
property. StringFormat
is missing in the bindings. - Style Setters do not allow binding their values.
- Generic Types or
x:Array
markup extension in XAML.
Notion of the Logical Tree
WPF and Avalonia adopted a notion of the Logical tree sparser than the Visual tree but containing most of the needed information. It is usually easier to operation with the logical tree because it has a smaller number of nodes and it closely matches the XAML. WinUI (or UWP) never had this notion.
Using RelativeSource with AncestorType Mode
Avalonia allows you to bind to a property higher up the visual or logical tree in XAML, for example:
<Grid Tag="Hello World">
<TextBlock Text="{Binding Path=Tag,
RelativeSource={RelativeSource AncestorType=Grid}}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
will bind Text
property of the TextBlock
to the Tag
property of the Grid
that contains it.
For properties defined on the elements up the logical tree, there is even a shortcut:
Text={Binding $parent[Grid].Tag}
Now why it is important - it happens many times that you need to bind to a property defined higher up on one of the trees - usually on logical tree, more rarely on a visual tree. For example, the background of a cell within a DataGrid
might depend on some properties defined on the DataGrid
's DataContext
, which the cell does not have access to (it only have access to the cell's DataContext
).
Inheriting Property Value down the Visual or Logical Tree
This feature is related to the one above - sometimes, you want the whole property to propagate down the visual or logical tree (unless otherwise specified). A great example of such built in property is DataContext
. WinUI wires in the propagation of the DataContext
dependency property but does not allow custom dependency and Attached properties to be inherited.
Both WPF and Avalonia allow it. Avalonia has inherit
argument to its RegisterAttached(...)
static
method.
Why is it important - for example, many times the DataContext
is busy with some other functionality e.g., in the 3rd party controls and you want to create your own custom data context to connect various visual parts of the application. Avalonia and WPF allow it, while WinUI based frameworks - do not.
MultiBinding
MultiBinding
is important when you want a visual property to depend on multiple other properties and change when either one of them is changing. WinUI does not have built-in functionality for MultiBinding
while both WPF and Avalonia - do.
Moreover, WPF does not allow recursive multibinding while Avalonia - does - meaning that some of the multibinding sources can be computed as a result of another multibinding.
x:Static Markup Extension
Both Avalonia and WPF offer it, while WinUI
nixed it.
x:Static
is very handy when you want to define a static
property in your C# and access it easily from WPF.
For example, if you have a stateless Binding Converter, you can create a static
instance property of that type within your Converter
class and access it from every binding within every XAML in projects referencing the converter DLL. Instead in WinUI, you have defined all your Converters as resources within some XAML resource file which is an extra unnecessary step and often leads to resource duplication.
Another great usage for x:Static
extension is for static Behaviors. For example, you are building a behavior that calls some method when PointerPressed
event occurs on a visual element. If you want to make the Behavior generic to fire any routed event specified by the developer - the best way it to connect the behavior (via a static
attached property) to the RoutedEvent
property defined as a Static
Property. for example:
<Grid myProj:MyBehavior.TheEvent="{x:Static InputElement.PointerPressedEvent}"/>
StringFormat
WinUI does not allow string
format in its bindings, while it is a very useful feature allowing to simplify the XAML code.
<TextBlock Text="{Binding Path=Value, StringFormat='Value={0}'}"/>
If say, the bound value equals 5
, then the TextBlock
will show:
Value=5
And it will work without the need for binding converters or multiple TextBlocks
.
Style Setter Values with the Bindings
Avalonia and WPF allow to bind the Style
Setter values to various properties on visual and non-visual objects. For example:
<Style x:Key="MyStyle">
<Setter Property="Background"
Value="{Binding Path=MyBrushDefinedInViewModel}"/>
</Style>
WinUI does not allow it.
Why is it important - because it gives a great way to customize the controls. For example, if you want some control template defined in your style to be customizable depending on some value - you create a corresponding dependency or attached property on the style, bind the property within your ControlTemplate
and bind the Style
property to the required variable. Unfortunately, it is impossible to do it in WinUI and you have to copy and paste your style with control templates in order to achieve the same effect.
The resulting XAML code can be much more re-usable in Avalonia (and WPF) than in WinUI based products.
Generic Types in XAML
AFAIK neither Uno nor MAUI allow using generic types in XAML, even though x:Array
is part of XAML specification.
WPF also has a problem with Generic Types - it only allows them on the root elements of XAML file.
Avalonia, however, has the full Generic Types support in XAML.
For example, you can define a list of string
s in XAML as follows:
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:generic_collections="clr-namespace:System.Collections.Generic;
assembly=System.Collections"
x:Class="NP.Demos.GenericTypesInXaml.Views.MainView">
<UserControl.Resources>
<generic_collections:List x:Key="TheList"
x:TypeArguments="x:String">
<x:String>Str1</x:String>
<x:String>Str2</x:String>
<x:String>Str3</x:String>
</generic_collections:List>
<UserControl.Resources>
</UserControl>
If you have a Generic
class, say:
public class MyGenericClass<T1, T2>
{
public T1? Val1 { get; set; }
public T2? Val2 { get; set; }
}
You can define an object of that type as an Avalonia resource as follows:
<views:MyGenericClass x:Key="MyInstance"
x:TypeArguments="x:Int32, x:String"
Val1="1"
Val2="Hello World 1"/>
Finally, a list of the objects of MyGenericClass
type can be defined in XAML as:
<generic_collections:List x:Key="ListOfGenericClasses"
x:TypeArguments="views:MyGenericClass(x:Int32, x:String)">
<views:MyGenericClass x:TypeArguments="x:Int32, x:String"
Val1="2"
Val2="Hello World 2"/>
<views:MyGenericClass x:TypeArguments="x:Int32, x:String"
Val1="3"
Val2="Hello World 3"/>
</generic_collections:List>
Conclusion
Avalonia is a great multiplatform framework that expanded its APIs and platforms to cover Web and Mobile on top of the desktop platforms.
It provides a lot of new features and can be called Multiplatform
WPF++.
In my view, it is better and closer to WPF than its competitors implementing WinUI functionality.
If your company is interested in Multiplatform
XAML/C# solutions, Avalonia is definitely worth a serious consideration.
Acknowledgement
A hat tip to my coworker and friend, Jon Sinsel, for pointing out to me the performance problems with WinUI Dependency Properties and the links detailing them.
History
- 20th August, 2023: Initial version