✔ 🏗️ Understand C# and Avalonia UI fundamentals
✔ 📋 Build a complete task management application
✔ 💾 Implement data persistence with JSON
✔ 🎨 Create a modern and intuitive user interface
If you've never worked with C# or modern user interfaces, this workshop is perfect for getting started. We'll build a task management application in two phases: first the essential features, then optional advanced improvements.
🤓 Actually, C# is an object-oriented programming language developed by Microsoft, designed to be simple, modern and powerful. Avalonia UI is a cross-platform user interface development framework that allows you to create native desktop applications for Windows, macOS and Linux with a single codebase.
Using C# with Avalonia UI offers several advantages:
- Simplicity 🎯: Clear and intuitive syntax, perfect for beginners
- Performance ⚡: Fast and responsive native applications
- Cross-platform 🌐: One application for all operating systems
- Rich ecosystem 🔧: Access to the huge .NET and NuGet library
- Productivity 🚀: Exceptional development tools with Visual Studio and VS Code
C# is a modern programming language specifically designed to develop robust and maintainable applications. It allows developers to create desktop, web, mobile and gaming applications with an elegant and expressive syntax. C# is based on the .NET platform and offers features like automatic memory management, object-oriented programming, and perfect integration with the Microsoft ecosystem. If you've never worked with C# before, check out the official documentation to understand the basics.
Please refer to the SETUP.md file.
Once setup is complete, verify everything works:
dotnet runAn Avalonia window should open with your base application.
Before diving into the tasks, let's understand how a C# project with Avalonia is organized:
src/
├── Models/
│ └── TaskItem.cs # Data model representing a task
├── Views/
│ └── MainWindow.axaml # Main UI layout (XAML file)
├── ViewModels/
│ └── MainWindowViewModel.cs # Logic behind the UI
├── Program.cs # Application entry point
└── App.axaml # Application-level configuration
TaskItem.cs: Contains the data structure for tasks (Title, IsCompleted, etc.)MainWindow.axaml: The visual interface layout (similar to HTML but for desktop apps)MainWindowViewModel.cs: Contains the business logic and data bindingProgram.cs: Starts the application and shows the main window
- Models define your data structure
- Views (
.axamlfiles) define the visual interface - ViewModels connect the data to the interface using data binding
- Program.cs orchestrates everything together
This separation allows you to modify the interface without changing the logic, and vice versa.
Focus: simple C# classes and basic data binding with Avalonia. No complex architecture.
In this step, you'll familiarize yourself with the TaskItem data model that represents a task in your application. The model is the data structure that contains all the information of a task. Understanding and mastering data models is fundamental in object-oriented programming.
In C#, properties are special class members that provide controlled access to private fields. They allow reading and writing values while encapsulating business logic if needed.
- Examine the
src/Models/TaskItem.csfile provided in the base project - ✅ Already implemented: The
TaskItemclass already contains:Title(string) - the task titleIsCompleted(bool) - the completion state of the task
- Optional: add a simple
Id(string or GUID) if it helps you manage selections, otherwise skip this part
In this step, you'll discover Avalonia UI's data binding. Data binding is a powerful mechanism that automatically synchronizes the user interface with your application data. When data changes, the UI updates automatically, and vice versa.
The CheckBox is a UI control that allows users to check or uncheck an option. By binding it to your task's IsCompleted property, you create a direct interaction between the interface and your data.
- Where to work: Open
src/Views/MainWindow.axaml- this is where the UI is defined - Find the task list: Look for the
ListBoxorItemsControlthat displays tasks - Add CheckBox: Inside each task item template, add a
CheckBoxcontrol - Data binding: Bind the
CheckBox'sIsCheckedproperty to the task'sIsCompletedproperty using{Binding IsCompleted} - Test: Ensure that when the user checks/unchecks the box, the task state updates immediately
The task list is likely displayed using a ListBox with an ItemTemplate. You'll need to modify this template to include the CheckBox alongside the task title.
- You can toggle the completion state of any task from the list
- The checkbox visual state correctly reflects the task's
IsCompletedstate
JSON serialization is the process of converting in-memory objects to a standardized text format (JSON) that can be stored in a file or transmitted over a network. This is an essential skill in modern development as JSON is the most widely used data exchange format.
System.Text.Json is Microsoft's recommended library for JSON serialization in .NET. It's performant, secure, and natively integrated into the framework.
- Add a button in the user interface with the text "Save to JSON"
- Implement the button click logic to:
- Create the
data/folder if it doesn't exist - Serialize the current task list to
data/tasks.json - Use
System.Text.Jsonfor serialization
- Create the
- Handle potential errors (permissions, disk space, etc.)
- After clicking the button, the
data/tasks.jsonfile is created/updated with your tasks - The JSON file contains all tasks with their properties correctly serialized
Deserialization is the reverse operation of serialization: it converts JSON data stored in a file into usable objects in your application. This step will teach you to manage application lifecycle and data persistence.
It's important to gracefully handle error cases: missing file, corrupted JSON, or permission issues. A robust application must work even if certain files are absent.
- Option A (recommended): On application startup, try to read
data/tasks.jsonand populate the task list - Option B: Add a separate "Load" button that imports from the same file
- Implement deserialization with
System.Text.Json - Handle error cases:
- Missing file: start with an empty list
- Invalid JSON: display an error message and start with an empty list
- If
data/tasks.jsonexists, tasks appear in the UI after launch (or when pressing Load) - The application works correctly even if the file doesn't exist
For this first part, we prioritize simplicity and understanding of basic concepts rather than complex architecture. This approach allows you to focus on learning C# and Avalonia without being distracted by advanced patterns.
- ✅ Store everything in a single list/collection in the code-behind or a simple view model
- ✅ Avoid repositories, services, or dependency injection for this part
- ✅ Focus on the proper functioning of basic features
- You can add tasks
- You can toggle completion state with a checkbox
- You can delete selected tasks (already present)
- You can save/load from JSON
Focus: improve the user experience and introduce light architecture if desired.
Tags (labels) are a powerful way to organize and categorize tasks. This feature will introduce you to string collections, text parsing, and more complex user interfaces with dynamic filters.
Chips or pills are compact UI elements that visually represent tags in an elegant and interactive way.
- Add a
Tagsfield (comma-separated) when creating/editing a task - Display tags as small chips/pills in the task list
- Implement a tag filter with an intuitive interface
- Handle tag validation and cleanup (removing spaces, duplicates, etc.)
- Users can add tags to their tasks
- Tags display in a visually appealing way
- The filter system works correctly
Date management is crucial in a task management application. This step will teach you to work with DateTime and DateOnly types, use date selection controls, and implement temporal filtering logic.
Quick filters (Today, This Week, Overdue) significantly improve the user experience by providing quick access to the most relevant tasks.
- Add a
DueDateproperty (nullable) toTaskItem - Integrate an Avalonia
DatePickerfor date selection - Implement quick filters:
- Today: tasks due today
- This week: tasks due in the next 7 days
- Overdue: tasks with a past date and not completed
- Add visual indicators for overdue tasks
- Users can assign due dates to tasks
- Temporal filters work correctly
- Overdue tasks are clearly identifiable
This step focuses on user experience (UX) and introducing a slightly more structured architecture. You'll learn to separate responsibilities and create more fluid and intuitive interactions.
Inline editing allows users to modify content directly without opening separate windows, significantly improving application fluidity.
- Implement inline editing of task titles (double-click to edit)
- Add global action buttons:
- Complete All: marks all tasks as completed
- Clear Completed: removes all finished tasks
- Optional: move file management to a light helper/service
- Improve animations and transitions for a smoother experience
- Inline editing works intuitively
- Global action buttons are functional
- The interface is more polished and professional
This final step will teach you to create a seamless user experience with auto-save and robust error handling. A professional application must function reliably even in case of unexpected problems.
- Implement auto-save on changes (instead of manual button)
- Add graceful error handling:
- Missing/corrupted JSON: recovery or reset
- Permission issues: informative error messages
- Insufficient disk space: appropriate handling
- Optional: add an automatic backup system
- Implement a save status indicator
- Users can add tags and due dates
- Status/tag/date filters work perfectly
- Data persists between application runs
- The application gracefully handles all error cases
System.Text.Jsonfor JSON serialization/deserialization- Avalonia bindings for
CheckBox.IsChecked<->bool ObservableCollection<T>for list data binding- File I/O with
File.ReadAllText/File.WriteAllText(create folder if needed) DateTime.NowandDateTime.Comparefor date managementstring.Split(',')andstring.Join(',')for tags
- C# classes and properties: Master OOP fundamentals
- Avalonia data binding and events: Create reactive interfaces
- JSON serialization: Handle modern data persistence
- Incremental delivery: From simple to advanced, professional methodology
- Error handling: Create robust and reliable applications
- User experience: Design intuitive and fluid interfaces
Congratulations! You've created your own task management application with C# and Avalonia UI. Throughout this workshop, you've learned the fundamentals of modern desktop application development and mastered essential object-oriented programming concepts.
Thank you for following this workshop! If you have any questions, don't hesitate to contact the PoC team.
You've discovered C# and Avalonia UI, but there are still many concepts to explore. Here are some examples:
- Entity Framework Core for database management
- ASP.NET Core for web applications
- MAUI for cross-platform mobile applications
- Blazor for web applications with C#
- SignalR for real-time applications
![]() Milo Kowalska |
|---|
🚀 Don't hesitate to follow us on our different platforms, and give a star 🌟 to PoC's repositories.
