Aplikacje mobilne · Trwałość danych
Preferences w .NET MAUI: zapamiętywanie ustawień
Wybrany motyw, imię użytkownika, włączone powiadomienia: to drobne wartości, dla których baza SQLite byłaby przesadą. Do tego służy Preferences: proste pary klucz-wartość, które przetrwają zamknięcie aplikacji.
- około 45 minut
- .NET MAUI · Preferences
- INF.04.6.2
Po tej lekcji: zapisać, odczytać i usunąć ustawienia przez Preferences.Default, zastosować zapisany motyw już przy starcie oraz wybrać właściwy mechanizm: Preferences, plik, SQLite czy SecureStorage.
Ustawienia zapamiętane między uruchomieniami
Użytkownik wybiera motyw raz, a nie przy każdym starcie. Porównamy zapisane ustawienie z chwilowym stanem pola i pokażemy, skąd bierze się wartość domyślna.
Najpierw uruchomisz mały ekran. Potem połączysz go z kodem i sprawdzisz konkretne wyniki. Dodatki wykonuj dopiero, gdy wersja podstawowa działa. Quiz i oceniane zadania pozostają w biurku po zalogowaniu.
Laboratorium · ćwiczenie w przeglądarce, do którego odsyłają rozgrzewki na końcu lekcji
1 · Sprawdź w działaniu
Zapisz, zamknij, uruchom ponownie
Wpisz imię, wybierz motyw „Ciemny” i kliknij „Zapisz ustawienia”. Obserwuj panel pamięci. Potem kliknij „Zamknij i uruchom ponownie”: formularz wraca do stanu początkowego i wczytuje zapisane wartości. Spróbuj też Remove(imię) i „Przywróć domyślne” (Clear).
Najpierw przewidź, potem sprawdź: W modelu Preferences zmień wartość, zapisz i symuluj ponowne uruchomienie. Porównaj stan UI z trwałą parą klucz–wartość.
Dane zapisane przez Set przeżywają restart. Clear usuwa wszystko, Remove jeden klucz, a Get z wartością domyślną nigdy nie zgłasza błędu braku klucza. Model pomaga zobaczyć mechanizm; właściwą aplikację uruchomisz z plików poniżej.
1. Przygotuj miejsce pracy
Co dodajesz, a co podmieniasz?
Stronę dodaj przez Projekt → Dodaj → Nowy element → .NET MAUI ContentPage (XAML). Powstaje para .xaml i .xaml.cs. Dla ContentView wybierz szablon ContentView; dla modeli i serwisów zwykłą klasę. Jeśli plik już istnieje, podmień wskazaną zawartość — nie twórz drugiej klasy o tej samej nazwie.
| Plik | Rola w ćwiczeniu |
|---|---|
| MainPage.xaml | Wygląd strony lub kontrolki |
| MainPage.xaml.cs | Logika i obsługa danych |
Zanim uruchomisz: trzy połączenia
x:Class="UstawieniaMauiApp.NazwaStrony" w XAML musi zgadzać się z namespace UstawieniaMauiApp i nazwą klasy C#. InitializeComponent() tworzy kontrolki opisane w XAML.
x:Name="PoleImie" daje kodowi C# dostęp przez PoleImie.Text. Z kolei Clicked="Zapisz_Clicked" wskazuje metodę o tej nazwie w pliku .xaml.cs. Sam napis przycisku w Text niczego nie podpina.
Gdy dodajesz XAML z obsługą zdarzeń, od razu uzupełnij też odpowiadający C#. Uruchamiaj dopiero po skończeniu oznaczonej pary plików; brakujący handler nie jest błędem środowiska.
2. Uruchom sam wygląd — jeszcze bez logiki
W świeżym projekcie zastąp MainPage.xaml poniższym ekranem. W MainPage.xaml.cs zachowaj konstruktor z InitializeComponent(); usuń szablonowy licznik i OnCounterClicked, bo nie ma ich już w XAML. Na tym etapie App i AppShell pozostają z szablonu. To pełny, tymczasowy XAML — później świadomie go podmienisz, nie dokleisz do drugiego ContentPage.
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="UstawieniaMauiApp.MainPage">
<VerticalStackLayout Padding="24" Spacing="14">
<Label Text="Moje ustawienia" FontSize="24" />
<Entry Placeholder="Imię" />
<Switch IsToggled="True" />
</VerticalStackLayout>
</ContentPage>
- Pierwsza próba Uruchom. Zobaczysz kontrolki, ale przyciski bez Clicked jeszcze nic nie robią. Sprawdź rozmiar i kolejność elementów. Zatrzymaj aplikację przed następnym etapem.
Zacznijmy od czytnika e-booków
Aplikacja, która pamięta
Czytnik e-booków pamięta rozmiar czcionki i motyw, aplikacja fitness jednostki (kg czy funty), lista zadań to, czy pokazywać wykonane pozycje. Każde z tych ustawień to jedna mała wartość. Preferences działa podobnie do localStorage w przeglądarce.
To nie jest baza danych: nie nadaje się do dużych list obiektów (SQLite) ani do haseł i tokenów (SecureStorage, które szyfruje zawartość).
2 · Pięć metod
Wszystko przez Preferences.Default
| Metoda | Zastosowanie |
|---|---|
Set(klucz, wartość) | Zapisuje wartość pod kluczem (nadpisuje, jeśli klucz istniał). |
Get(klucz, domyślna) | Odczytuje wartość. Gdy klucza brak, zwraca wartość domyślną i nie zgłasza wyjątku. |
ContainsKey(klucz) | Sprawdza, czy klucz został kiedykolwiek zapisany. |
Remove(klucz) | Usuwa jedną wartość. |
Clear() | Usuwa wszystkie preferencje aplikacji. |
6 · Trzy poziomy trwałości
Preferences, plik czy SQLite?
| Mechanizm | Do czego | Przykład |
|---|---|---|
Preferences | Małe, pojedyncze ustawienia | motyw, imię, przełącznik |
| Plik (TXT / JSON) | Dane średniej wielkości | notatka, eksport |
| SQLite | Duże, ustrukturyzowane zbiory | lista zamówień, produkty |
SecureStorage | Dane wrażliwe | token logowania |
3. Wskaż stronę startową ćwiczenia
Po dodaniu docelowych stron podmień App.xaml.cs na poniższy. App.xaml zostaje z szablonu. Od tej chwili startuje MainPage, a nie wcześniejszy tymczasowy MainPage z AppShell. Uzupełnij jej pliki w kolejnych etapach, zanim ponownie uruchomisz projekt.
namespace UstawieniaMauiApp;
public partial class App : Application
{
public App() => InitializeComponent();
protected override Window CreateWindow(IActivationState? activationState)
=> new Window(new NavigationPage(new MainPage()));
}
CreateWindowTworzy okno aplikacji. NavigationPage jest kontenerem zwykłych stron i daje przycisk powrotu; nie łączymy go z Shell.new MainPage()Tworzy instancję docelowej strony. Aby testować drugi niezależny przykład, zatrzymaj program, zmień tylko ten typ i uruchom ponownie.
4. Połącz wygląd z działaniem
Teraz zbuduj docelowy przykład. Pełne pliki poniżej zastępują swoje wcześniejsze wersje. Przeczytaj opis nad kodem i objaśnienia pod nim; potem sprawdź przepływ danych, nie tylko brak czerwonych podkreśleń.
Gdy przykład ma kilka plików zależnych od siebie, najpierw dodaj wszystkie wskazane typy, a potem uruchom całość. Ustaw breakpoint w obsłudze głównego przycisku i prześledź jedną próbę.
Budowa krok po kroku
MainPage.xaml
Dodaj lub otwórz MainPage.xaml i podmień jego zawartość. Najpierw odszukaj kontener, potem nazwane kontrolki oraz wskazane zdarzenia. Pozostaw zgodne x:Class i nazwę klasy w pliku .xaml.cs.
Pole imienia, Picker z motywem, Switch powiadomień i dwa przyciski.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="UstawieniaMauiApp.MainPage"
Title="Ustawienia">
<VerticalStackLayout Padding="24" Spacing="14">
<Label Text="Ustawienia użytkownika" FontSize="24" FontAttributes="Bold" />
<Entry x:Name="ImieEntry" Placeholder="Imię użytkownika" />
<Picker x:Name="MotywPicker" Title="Wybierz motyw">
<Picker.Items>
<x:String>Systemowy</x:String>
<x:String>Jasny</x:String>
<x:String>Ciemny</x:String>
</Picker.Items>
</Picker>
<HorizontalStackLayout>
<Label Text="Powiadomienia" VerticalOptions="Center" />
<Switch x:Name="PowiadomieniaSwitch" />
</HorizontalStackLayout>
<Button Text="Zapisz ustawienia" Clicked="Zapisz_Clicked" />
<Button Text="Przywróć domyślne" Clicked="Wyczysc_Clicked" />
<Label x:Name="StatusLabel" />
</VerticalStackLayout>
</ContentPage>
- Przeczytaj powiązanie x:Name identyfikuje kontrolkę, a Binding odczytuje właściwość obiektu ustawionego jako BindingContext. To dwa różne mechanizmy.
Budowa krok po kroku
MainPage.xaml.cs
Stały klucz identyfikuje ustawienie. Get przyjmuje wartość domyślną, Set utrwala wartość. Nie przechowuj tu hasła — Preferences nie jest magazynem sekretów.
Klucze jako stałe, wczytanie przy starcie, zapis po kliknięciu i switch zamieniający indeks na motyw.
using Microsoft.Maui.Storage;
namespace UstawieniaMauiApp;
public partial class MainPage : ContentPage
{
private const string KluczImie = "uzytkownik_imie";
private const string KluczMotyw = "uzytkownik_motyw";
private const string KluczPowiadomienia = "uzytkownik_powiadomienia";
public MainPage()
{
InitializeComponent();
WczytajUstawienia();
}
private void WczytajUstawienia()
{
ImieEntry.Text = Preferences.Default.Get(KluczImie, "");
MotywPicker.SelectedIndex = Preferences.Default.Get(KluczMotyw, 0);
PowiadomieniaSwitch.IsToggled = Preferences.Default.Get(KluczPowiadomienia, true);
ZastosujMotyw(MotywPicker.SelectedIndex);
}
private void Zapisz_Clicked(object sender, EventArgs e)
{
Preferences.Default.Set(KluczImie, ImieEntry.Text ?? "");
Preferences.Default.Set(KluczMotyw, MotywPicker.SelectedIndex);
Preferences.Default.Set(KluczPowiadomienia, PowiadomieniaSwitch.IsToggled);
ZastosujMotyw(MotywPicker.SelectedIndex);
StatusLabel.Text = "Ustawienia zostały zapisane.";
}
private void Wyczysc_Clicked(object sender, EventArgs e)
{
Preferences.Default.Clear();
WczytajUstawienia();
StatusLabel.Text = "Przywrócono ustawienia domyślne.";
}
private static void ZastosujMotyw(int indeks)
{
Application.Current!.UserAppTheme = indeks switch
{
1 => AppTheme.Light,
2 => AppTheme.Dark,
_ => AppTheme.Unspecified
};
}
}
const string KluczImie = ...Literówka w stałej to błąd kompilacji, a literówka w tekście to cicha, trudna do znalezienia niezgodność.Get(KluczImie, "")Typ wartości domyślnej (string,int,bool) wyznacza typ wyniku.ImieEntry.Text ?? ""Textmoże byćnull, aSetoczekuje tekstu.ZastosujMotyww dwóch miejscach Przy starcie (użytkownik od razu widzi swój motyw) i po zapisie (zmiana bez restartu).indeks switch { 1 => ..., 2 => ..., _ => ... }Wyrażenieswitchjest zwięźlejsze niż seriaif / else if.Application.Current.UserAppThemewymusza jasny lub ciemny wygląd niezależnie od systemu.Preferences.Default.Clear()Usuwa wszystko, więc po nim wywołujemyWczytajUstawienia(), aby formularz pokazał wartości domyślne.
5. Odbiór: czy naprawdę działa?
Wykonaj próby w swojej aplikacji, nie tylko w modelu na stronie. Zaznaczaj dopiero po sprawdzeniu wyniku. Funkcje urządzenia wymagają testu na właściwej platformie.
5 · Czego unikać
Trzy pułapki Preferences
Hasła i tokeny w Preferences
Preferences.Default.Set("token", token);Preferences nie szyfruje danych, więc wartość może zostać odczytana.
await SecureStorage.Default.SetAsync("token", token);Dane wrażliwe trafiają do SecureStorage.
Cała lista lub obiekt w Preferences
Preferences.Default.Set("lista", mojaLista);Mechanizm obsługuje tylko proste typy, więc kod się nie skompiluje.
Preferences.Default.Set("lista", JsonSerializer.Serialize(mojaLista));Serializacja do JSON to obejście. Zwykle to znak, że lepiej użyć pliku lub SQLite.
Zła wartość domyślna
string imie = Preferences.Default.Get(KluczImie, 0);Wartość domyślna 0 sprawia, że Get zwraca int, więc przypisanie do string się nie skompiluje.
string imie = Preferences.Default.Get(KluczImie, "");Typ wartości domyślnej określa typ wyniku.
Ćwiczenie z pomocą · samodzielna praca
6. Mała zmiana, którą zrobisz samodzielnie
Dodaj ustawienie Rozmiar tekstu o wartości domyślnej18.
Dodaj ustawienie Rozmiar tekstu o wartości domyślnej18. Dotychczasowe działanie ma pozostać poprawne.
? Potrzebujesz pomocy? Rozwiązuj krok po kroku.
Krok 1 — pokaż podpowiedź
Dodaj suwak albo Picker i stały klucz, np. rozmiar_tekstu.
Krok 2 — pokaż podpowiedź
Użyj tego samego typu przy Get i Set.
Krok 3 — pokaż podpowiedź
Przy wczytywaniu zastosuj rozmiar do Label oraz sprawdź zachowanie po wyczyszczeniu.
Otwórz tylko tyle podpowiedzi, ile potrzebujesz. Po każdym kroku wróć do zadania i sprawdź wynik.
7 · Sprawdź się
Gdzie to zapisać?
Cztery sytuacje.
Podsumowanie
Co warto zapamiętać
Preferences.Defaultprzechowuje małe wartości jako pary klucz-wartość i zachowuje je po restarcie.Set,Get(z wartością domyślną),ContainsKey,Remove(jeden klucz) iClear(wszystko).- Klucze trzymaj w stałych
const. Zapisany motyw stosuj od razu przy starcie. - Dane wrażliwe:
SecureStorage. Listy i obiekty: plik lub SQLite.
Dalej na swoim koncie
Rozgrzewki, quiz i zadania są w biurku ucznia.
Teoria jest otwarta dla wszystkich. Żeby rozwiązywać zadania, zapisywać szkice i widzieć swój postęp, zaloguj się.
Zaloguj się →