Przykładowa aplikacja .NET MAUI pokazująca wzorzec dla dużego ekranu złożonego
z kilku ContentView, gdzie każdy child view ma własny ViewModel.
Projekt jest celowo zbudowany w C# Markup, bez XAML.
DashboardPagetworzy child viewy przezIServiceProvider.GetRequiredService<T>().- Każdy child (
AppointmentsView,TasksView,CustomersView) ma własny ViewModel. - Konstruktory View i ViewModeli nie uruchamiają żadnego LoadData.
OnAppearinggłównej strony uruchamia inicjalizację dopiero po utworzeniu UI.- Najważniejszy child jest ładowany pierwszy.
- Pozostałe niezależne childy są ładowane później przez
Task.WhenAll. - Opuszczenie strony anuluje operacje przez
CancellationToken. AsyncViewModelBaseblokuje podwójneInitializeAsync.CustomersViewModelpokazuje paginację po 50 rekordów przezRemainingItemsThreshold.- Pierwszy load podmienia całą
ObservableCollection, zamiast wykonywać tysiąceAdd. - Fake repositories symulują wolne SQLite/API.
Nie:
Dashboard constructor
-> GetRequiredService<ChildView>()
-> ChildView constructor
-> LoadData()
Tylko:
Dashboard constructor
-> tworzy View + ViewModel
-> buduje Grid
-> brak I/O
OnAppearing
-> render UI
-> InitializeAsync najważniejszego childa
-> InitializeAsync pozostałych
MauiAsyncViewsDemo
├── Contracts
│ ├── IAsyncChildView.cs
│ └── IAsyncInitializable.cs
├── Models
├── Repositories
│ ├── I...Repository.cs
│ └── Fake...Repository.cs
├── ViewModels
│ ├── AsyncViewModelBase.cs
│ ├── AppointmentsViewModel.cs
│ ├── TasksViewModel.cs
│ └── CustomersViewModel.cs
├── Views
│ ├── DashboardPage.cs
│ ├── AppointmentsView.cs
│ ├── TasksView.cs
│ └── CustomersView.cs
├── App.cs
├── MauiProgram.cs
└── MauiAsyncViewsDemo.csproj
Projekt używa:
CommunityToolkit.Maui.MarkupCommunityToolkit.Mvvm
W Fake...Repository zamień Task.Delay na właściwe operacje async:
await httpClient.GetFromJsonAsync(..., cancellationToken);lub:
await dbContext.Entities
.AsNoTracking()
.ToListAsync(cancellationToken);Dla SQLite użyj API, które faktycznie wykonuje zapytania asynchronicznie.
Nie otaczaj I/O bez potrzeby w:
Task.Run(...)Task.Run zostaw dla kosztownej pracy CPU, nie dla zwykłego await HTTP/DB.
Kolejne dobre kroki:
- osobny
NavigationService, BasePage,- cache danych i polityka odświeżania,
RefreshAsync,- limit równoległości przy 8-10 child ViewModelach,
- skeleton loading,
- realny SQLite repository,
- wersja z Telerik
RadCollectionView, - testy ViewModeli.