Understanding the Model-View-ViewModel architectural pattern.
The Model-View-ViewModel pattern (MVVM) is a common way of structuring a UI application. It takes advantage of Avalonia's binding system to separate the logic of the application from the display of the application.
MVVM might be overkill for a simple application, but as applications grow over time, they usually reach a point where tracking logic in code-behind becomes problematic for two main reasons:
- The interactions between UI components becomes overly complicated and error-prone
- It's very difficult to unit test code in code-behind
MVVM solves this by abstracting the user interface into regular .NET classes that can be unit tested like any other classes.
This is intended as a brief introduction to MVVM, there are many resources online that go into this subject in more depth.
First of all, MVVM has overhead in terms of complexity.
Because the advantages of using the MVVM pattern usually only become apparent when an application becomes more complex, it is often difficult to understand from simple examples why MVVM should be used. Indeed if your application is going to remain small, using code-behind may well be easier to understand and maintain.
Many people prefer to start off their application using code-behind and once this starts proving problematic, refactor to use the MVVM pattern. This step usually happens while the application is relatively simple so generally doesn't take too much time.
When we talk about the MVVM pattern, the most important parts are the View layer and the ViewModel layer. Views are usually implemented as
UserControls while ViewModels are .NET classes.
One way to imagine an MVVM application is to imagine these two layers as hovering over one another, connected by bindings:
Diagram of MVVM
The above example has, at the View layer:
MainWindowwhich is an Avalonia
Documentwhich is an Avalonia
- Various bindings, indicated by arrows
At the ViewModel layer there are .NET classes which mirror the view layer:
MainWindowViewModelwhich has a property containing;
- Two methods:
The ViewModel layer knows nothing of the view layer, so it is independent of Avalonia. Each View usually has a corresponding ViewModel which contains all of the logic for the View. The View layer is connected to the ViewModel layer by bindings. Because the ViewModel layer is independent of Avalonia, it can be unit tested like any other code.
The Model layer is the lowest layer in an MVVM application. Models usually represent data read from a database, or classes from a low-level library which implements the business logic of the application. The Model layer will be very specific to each application.
An example of a model might be a table row read from a database using Entity Framework.
In addition, most applications will add services to this mix, which usually implement the reading and writing of models and other application-specific logic.
There are a number of frameworks designed to help write applications using the MVVM pattern. ReactiveUI is one of the most popular and has support for Avalonia which can be added via the Avalonia.ReactiveUI NuGet package.