DEV Community

Abdul Rehman
Abdul Rehman

Posted on

Login Screen: Get started with Avalonia UI in JetBrains Rider IDE C# dotnet MVVM

Avalonia UI is Open Source alternative to Microsoft's WPF for building cross platform application in C#.Net. We are going to use dotnet sdk 9 in this tutorial and will help you get started with it and to build a basic Login Page Example in dotnet sdk 9 and JetBrain's Rider IDE which comes with free non comerial Licence. JetBrain's IDEs are no doubt one of the best IDEs and their ecosystem is very strong. But the real problem is pricing and most of the times when someone don't want to purchase the non comercial free linces is a great option from JetBrain.

Install DotNet SDK

The first step after installing the JetBrains IDE is to install the dotnet SDK. I would prefer to download and install the SDK by myself rather relaying on the IDE installation. After installation is done you should add the SDK path to the system veriable so that you be able to access the sdk via command line. If everything is setup you should be able to run the following command

dotnet --version
Enter fullscreen mode Exit fullscreen mode

and it should return the SDK 9 version information. If you have multiple SDK versions installed, you can use following command to check list all the available SDKs in your system.

dotnet --list-sdks
Enter fullscreen mode Exit fullscreen mode

Install Avalonia UI template

Now that we have dotnet sdk installed and it is available in our cmd terminal, we are good to install the Avalonia UI Template. For this you can simply run the following command.

dotnet new install Avalonia.Templates
Enter fullscreen mode Exit fullscreen mode

This will install and create a project with this template if you are in a right directory but we will skip the project creation process and we will jump into the JetBrains's Rider IDE for this purpose.

Create New Avalonia UI Project

Open the JetBrain's Rider IDE and in new project creation window click on New Solution Button.

JetBrain Rider IDE Open Project Screen

Now that you have Here on the left panel you will see the Avalonia UI Project Creation option. I will select the Avalonia MVVM App. You can also choose other options but for this tutorial we are going with the following settings

JetBrain Rider IDE New Project Creation

Don't forget to choose C# as your language instead of F#, and select the SDK 9 for the dotnet SDK. Now you are good to start coding. One more thing I forgot to mention, You should go with ReactiveUI when asked instead of Community UI.

Understanding the Folder Structure

Now that you are inside of your project you should see the folder structure. You can simply see your main.axaml file under the views directory. You should keep in mind that Avalonia UI uses it's own file structure which is axaml as mentioned in their official documentation.

MainWindow.axaml

Here you can see the App.axaml.cs file where the mainwindow is being initialized and started as a first window.

App.axaml.cs file

ViewModel for MainWindow

Now all you have to do is to move to your viewmodel directory and navigate to the file named MainWindowViewModel.cs. This file is your main View Model for your Main Window. You can change it to include the necessary variables and some initializations. Here is what my MainWindowViewModel.cs file looks like.

using ReactiveUI;
using System;
using System.Reactive;
using System.Diagnostics;
using Avalonia.Media;

namespace AvaloniaApplication2.ViewModels;

public class MainWindowViewModel : ViewModelBase
{
    private string _username;
    public string Username
    {
        get => _username;
        set => this.RaiseAndSetIfChanged(ref _username, value);
    }

    private string _password;
    public string Password
    {
        get => _password;
        set => this.RaiseAndSetIfChanged(ref _password, value);
    }

    private string _statusMessage;
    public string StatusMessage
    {
        get => _statusMessage;
        set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
    }

    public ReactiveCommand<Unit, Unit> LoginCommand { get; }

    public MainWindowViewModel()
    {
        // Define the dummy login credentials
        const string DUMMY_USERNAME = "admin";
        const string DUMMY_PASSWORD = "password123";

        // Create the ReactiveCommand for the login action
        LoginCommand = ReactiveCommand.Create(() =>
        {
            // Clear previous status message
            StatusMessage = string.Empty;

            // Simple validation check
            if (string.IsNullOrWhiteSpace(Username) || string.IsNullOrWhiteSpace(Password))
            {
                StatusMessage = "Please enter both username and password.";
                Debug.WriteLine("Login failed: Empty credentials.");
                return;
            }

            // Dummy login logic
            if (Username.Equals(DUMMY_USERNAME, StringComparison.OrdinalIgnoreCase) && Password == DUMMY_PASSWORD)
            {
                StatusMessage = "Login successful!";
                Debug.WriteLine($"Login successful for user: {Username}");
                // You can add navigation or other logic here upon successful login
            }
            else
            {
                StatusMessage = "Invalid username or password.";
                Debug.WriteLine("Login failed: Invalid credentials.");
            }
        });
    }
}

Enter fullscreen mode Exit fullscreen mode

Implements MVVM with ReactiveUI using ViewModelBase that inherits from ReactiveObject

Defines 3 bindable properties with RaiseAndSetIfChanged:

Username (string) – stores user input

Password (string) – stores password input

StatusMessage (string) – shows login status feedback

Exposes a ReactiveCommand named LoginCommand:

Created using ReactiveCommand.Create(...)

Executes login logic when invoked (bound to Login button)

Login validation logic inside command:

Checks for empty Username or Password

Compares input against hardcoded values:

Username: admin

Password: password123
Enter fullscreen mode Exit fullscreen mode

Updates StatusMessage based on result

Writes debug info using Debug.WriteLine(...)

Usage in XAML

Now it's time to use our ViewModel into our Main.axaml file for building our frontend UI. Here is main variables which we are going to use in our frontend.

  • Binds TextBox.Text to Username and Password
  • Binds Button.Command to LoginCommand
  • Displays StatusMessage to inform user of success or failure

No navigation yet, but placeholder comment added for future logic

Here is my complete Login Page UI code in XML


<reactiveUi:ReactiveWindow x:TypeArguments="viewModels:MainWindowViewModel"
                           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"
                           xmlns:reactiveUi="clr-namespace:Avalonia.ReactiveUI;assembly=Avalonia.ReactiveUI"
                           xmlns:viewModels="clr-namespace:AvaloniaApplication2.ViewModels"
                           mc:Ignorable="d"
                           x:Class="AvaloniaApplication2.Views.MainWindow"
                           x:DataType="viewModels:MainWindowViewModel"
                           Title="Login"
                           Width="420"
                           Height="500"
                           CanResize="False"
                           WindowStartupLocation="CenterScreen"
                           Background="#121826"
                           RequestedThemeVariant="Dark"
                           >

    <Border CornerRadius="20"
            Padding="30"
            Width="360"
            Background="#1F2937CC"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            BoxShadow="0 0 40 0 #00000080">

        <StackPanel Spacing="20">
            <TextBlock Text="Welcome Back"
                       FontSize="26"
                       Foreground="White"
                       FontWeight="SemiBold"
                       HorizontalAlignment="Center" />

            <TextBlock Text="Login to your account"
                       FontSize="14"
                       Foreground="#9CA3AF"
                       HorizontalAlignment="Center"
                       Margin="0,0,0,10"/>

            <StackPanel>
                <TextBlock Text="Username" Foreground="#9CA3AF" FontSize="12" Margin="0,0,0,5"/>
                <TextBox Text="{Binding Username, Mode=TwoWay}"
                         Background="#2C3444"
                         Foreground="White"
                         CornerRadius="8"
                         BorderBrush="Transparent"
                         Padding="8"/>
            </StackPanel>

            <StackPanel>
                <TextBlock Text="Password" Foreground="#9CA3AF" FontSize="12" Margin="0,10,0,5"/>
                <TextBox Text="{Binding Password, Mode=TwoWay}"
                         PasswordChar="●"
                         Background="#2C3444"
                         Foreground="White"
                         CornerRadius="8"
                         BorderBrush="Transparent"
                         Padding="8"/>
            </StackPanel>

            <TextBlock Text="{Binding StatusMessage}" 
                       Foreground="White" 
                       HorizontalAlignment="Center" 
                       Margin="0, -10, 0, 10" />

            <Button Content="Login"
                    Command="{Binding LoginCommand}"
                    Background="#4F46E5"
                    Foreground="White"
                    FontWeight="SemiBold"
                    CornerRadius="8"
                    Padding="12"
                    Width="100"
                    HorizontalAlignment="Center">
                <Button.Styles>
                    <Style Selector="Button:pointerover">
                        <Setter Property="Background" Value="#6366F1"/>
                    </Style>
                </Button.Styles>
            </Button>
            <TextBlock HorizontalAlignment="Center" Margin="0,10,0,0">
                <Run Text="Don't have an account? " Foreground="#9CA3AF"/>
                <Run Text="Register" Foreground="#4F46E5" TextDecorations="Underline" />
            </TextBlock>


        </StackPanel>
    </Border>
</reactiveUi:ReactiveWindow>

Enter fullscreen mode Exit fullscreen mode

Login Backend

Here is simple Main.axaml.cs file for handling the frontend UI control for simulating a dummy login process based on our MainViewModel


using System;
using Avalonia.Input;
using Avalonia.ReactiveUI;
using AvaloniaApplication2.ViewModels;
using ReactiveUI;

namespace AvaloniaApplication2.Views;

public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
{
    public MainWindow()
    {
        InitializeComponent();
        this.WhenActivated(disposables => { });
    }
    private void OnRegisterClicked(object? sender, PointerPressedEventArgs e)
    {
        Console.WriteLine("Register clicked"); // replace with navigation
    }

}

Enter fullscreen mode Exit fullscreen mode

Mostly everything is handled in the viewmodel and nothing much required here. Only the Navigation to Registration page is left which we would do in some upcoming tutorials. This is how our final UI looks like

Dark mode Avalonia UI Desktop Application for Login Page

Top comments (0)