Obsługa plików (TXT i JSON) w .NET MAUI (wersja prosta)

Wprowadzenie — po co pliki?

Aplikacja traci dane po zamknięciu. Pliki pozwalają je zachować na dysku i wczytać przy kolejnym uruchomieniu.
W praktyce: notatnik (TXT), listy danych (JSON). To jest dokładnie to, czego wymaga INF.04: zapisz → zamknij → uruchom → wczytaj i pokaż.

Co tworzymy w projekcie (Visual Studio 2022)

  1. Dwie strony:
    TxtPage.xaml – notatnik TXT
    JsonPage.xaml – lista imion do JSON

Jak dodać stronę: Solution Explorer → prawy klik na projekt → Add → New Item → .NET MAUI ContentPage (XAML).


Część A – Notatnik TXT (zapis/odczyt jednego tekstu)

TxtPage.xaml

<?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="PlikiDemo.TxtPage"
             Title="Notatnik TXT">

  <VerticalStackLayout Padding="16" Spacing="12">
    <!-- Pole wielowierszowe: użytkownik wpisuje treść -->
    <Editor x:Name="NotatkaEditor" HeightRequest="150" Placeholder="Wpisz notatkę..."/>

    <!-- Dwa przyciski: zapis i odczyt pliku -->
    <HorizontalStackLayout Spacing="8">
      <Button Text="Zapisz"  Clicked="Zapisz_Click"/>
      <Button Text="Wczytaj" Clicked="Wczytaj_Click"/>
    </HorizontalStackLayout>

    <!-- Informacje zwrotne dla użytkownika -->
    <Label x:Name="Status" TextColor="Gray"/>
  </VerticalStackLayout>
</ContentPage>

TxtPage.xaml.cs

namespace PlikiDemo;

public partial class TxtPage : ContentPage
{
    // 1) Wyznaczamy pełną ścieżkę do pliku w katalogu aplikacji
    // FileSystem.AppDataDirectory = bezpieczne miejsce na dane (Android/iOS/Windows/macOS)
    string path = Path.Combine(FileSystem.AppDataDirectory, "notatka.txt");

    public TxtPage()
    {
        InitializeComponent(); // 2) Tworzy kontrolki z XAML i łączy je z tą klasą
    }

    // 3) Zapis - nadpisuje plik zawartością pola Editor
    private async void Zapisz_Click(object sender, EventArgs e)
    {
        await File.WriteAllTextAsync(path, NotatkaEditor.Text ?? "");
        Status.Text = "Zapisano plik.";
    }

    // 4) Odczyt - jeśli plik istnieje, wczytujemy go do Editor
    private async void Wczytaj_Click(object sender, EventArgs e)
    {
        if (File.Exists(path))
        {
            NotatkaEditor.Text = await File.ReadAllTextAsync(path);
            Status.Text = "Wczytano plik.";
        }
        else
        {
            Status.Text = "Plik nie istnieje (zapisz coś najpierw).";
        }
    }
}

Co się właśnie stało?

  • Ustaliliśmy lokalizację pliku: AppDataDirectory/notatka.txt.
  • WriteAllTextAsync zapisało treść z Editor do pliku.
  • ReadAllTextAsync odczytało tekst i wstawiło go z powrotem do Editor.
  • Status pokazuje, co zrobiono, więc użytkownik nie błądzi.

Część B – Lista JSON (zapis/odczyt listy stringów)

JsonPage.xaml

<?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="PlikiDemo.JsonPage"
             Title="Lista JSON">

  <VerticalStackLayout Padding="16" Spacing="10">

    <!-- Wpisywanie nowej pozycji (np. imię) -->
    <Entry x:Name="ImieEntry" Placeholder="Wpisz imię"/>
    <Button Text="Dodaj" Clicked="Dodaj_Click"/>

    <!-- Lista elementów na ekranie -->
    <CollectionView x:Name="Lista" HeightRequest="200">
      <CollectionView.ItemTemplate>
        <DataTemplate>
          <!-- Tu każdy element to zwykły string -->
          <Label Text="{Binding}" FontSize="18"/>
        </DataTemplate>
      </CollectionView.ItemTemplate>
    </CollectionView>

    <!-- Zapis/odczyt JSON -->
    <HorizontalStackLayout Spacing="8">
      <Button Text="Zapisz JSON"  Clicked="ZapiszJson_Click"/>
      <Button Text="Wczytaj JSON" Clicked="WczytajJson_Click"/>
    </HorizontalStackLayout>
  </VerticalStackLayout>
</ContentPage>

JsonPage.xaml.cs

using System.Text.Json;

namespace PlikiDemo;

public partial class JsonPage : ContentPage
{
    // 1) Ścieżka do pliku JSON w katalogu aplikacji
    string path = Path.Combine(FileSystem.AppDataDirectory, "imiona.json");

    // 2) Pamięciowa lista danych (RAM)
    List<string> imiona = new();

    public JsonPage()
    {
        InitializeComponent(); // tworzy kontrolki z XAML
    }

    // 3) Dodaj nowy element do listy (w RAM) i odśwież widok
    private void Dodaj_Click(object sender, EventArgs e)
    {
        if (!string.IsNullOrWhiteSpace(ImieEntry.Text))
        {
            imiona.Add(ImieEntry.Text.Trim());

            // Odświeżenie CollectionView: najpierw wyczyść, potem przypisz
            Lista.ItemsSource = null;
            Lista.ItemsSource = imiona;

            ImieEntry.Text = "";
        }
    }

    // 4) Zapis listy do pliku w formacie JSON
    private async void ZapiszJson_Click(object sender, EventArgs e)
    {
        // Serialize: lista -> tekst JSON
        var json = JsonSerializer.Serialize(imiona);
        await File.WriteAllTextAsync(path, json);
        await DisplayAlert("Informacja", "Zapisano dane do JSON.", "OK");
    }

    // 5) Odczyt listy z pliku JSON do RAM i odświeżenie widoku
    private async void WczytajJson_Click(object sender, EventArgs e)
    {
        if (File.Exists(path))
        {
            // Odczyt tekstu i Deserialize: tekst JSON -> lista
            var json = await File.ReadAllTextAsync(path);
            imiona = JsonSerializer.Deserialize<List<string>>(json) ?? new List<string>();

            Lista.ItemsSource = null;
            Lista.ItemsSource = imiona;
        }
        else
        {
            await DisplayAlert("Informacja", "Plik nie istnieje – zapisz dane najpierw.", "OK");
        }
    }
}

Co się właśnie stało?

  • Zbierasz dane do listy w pamięci (List<string>).
  • Serialize zamienia listę na tekst JSON i zapisuje do pliku.
  • Deserialize wczytuje plik i tworzy z niego listę z powrotem.
  • CollectionView pokazuje to, co ma w ItemsSource, więc po każdej zmianie odświeżamy przypisanie.

Najczęstsze błędy i szybkie naprawy

  • Plik nie istnieje” przy odczycie → najpierw zapisz, potem wczytaj.
  • Lista się nie odświeża” → zrób Lista.ItemsSource = null; Lista.ItemsSource = imiona;.
  • Ścieżki buduj zawsze przez Path.Combine(FileSystem.AppDataDirectory, "nazwa.ext").
  • Puste wpisy? → Sprawdzaj string.IsNullOrWhiteSpace(...) przed dodaniem.
  • Długi zapis/odczyt? → używaj async (ReadAllTextAsync/WriteAllTextAsync), tak jak w przykładzie.

Podsumowanie

  • Poznałeś najprostszy sposób zapisu i odczytu plików w MAUI:
    TXT → WriteAllTextAsync/ReadAllTextAsync,
    JSON → JsonSerializer.Serialize/Deserialize.
  • Wiesz, gdzie zapisywać: FileSystem.AppDataDirectory.
  • Umiesz odświeżyć widok po zmianie danych.
  • To wystarczy, żeby zaliczyć typowe zadania INF.04 związane z plikami.