1. Cel aplikacji
Napisz aplikację WPF, która pozwala dodawać wydatki (nazwa, kategoria, kwota, data), wyświetlać je na liście, filtrować po roku i miesiącu oraz obliczać sumę wydatków dla wybranego miesiąca. Dane zapisz/odczytuj z pliku JSON w katalogu danych użytkownika.
2. Wymagania funkcjonalne
- Formularz „Nowy wydatek”:
Nazwa (tekst), Kategoria (lista: Jedzenie, Transport, Rachunki, Rozrywka, Zdrowie, Inne), Kwota (liczba > 0), Data (DatePicker), przycisk Dodaj. - Lista (DataGrid) z kolumnami: Nazwa, Kategoria, Kwota, Data.
- Filtry: pola Rok i Miesiąc (1–12). Zmiana filtrów natychmiast odświeża widok listy i Sumę miesiąca.
- Suma miesiąca wyświetlana obok filtrów w formacie
0.00 PLN. - Akcje: Zapisz (utrwal dane do JSON), Wczytaj (odczytaj JSON), Usuń zaznaczony.
- Walidacja pól formularza „na żywo” (czerwone obramowanie w WPF):
Nazwa – wymagana, max 50 znaków; Kategoria – wymagana; Kwota – > 0; Data – wymagana.
Dodaj aktywne tylko, gdy wszystkie pola są poprawne.
3. Wymagania techniczne i nazewnictwo (trzymaj się tej struktury)
DomowyBudzetWpf
├─ MainWindow.xaml
├─ MainWindow.xaml.cs
├─ Models
│ └─ dane.cs // model danych Wydatek (+ walidacja)
├─ Walidacja
│ └─ WalidacjaBudzet.cs // helper walidacji + RelayCommand (komendy)
└─ Logika
└─ LogikaBudzet.cs // logika/binding/filtr/suma/zapis-odczyt
Nowe elementy i co robią:
- IDataErrorInfo – interfejs, z którego WPF pobiera komunikaty walidacji; dzięki temu pojawia się czerwone obramowanie.
- RelayCommand – prosta klasa komend; spina przyciski z metodami w logice.
- ICollectionView.Filter – filtruje widok danych bez zmiany samej kolekcji.
4. Interfejs – opis rozmieszczenia
- Góra: GroupBox „Nowy wydatek” z czterema polami i przyciskiem Dodaj po prawej.
- Poniżej: pasek filtrów (Rok, Miesiąc), etykieta „Suma miesiąca: … PLN”, przyciski Zapisz i Wczytaj.
- Środek: DataGrid z kolumnami Nazwa, Kategoria, Kwota, Data.
- Dół: przycisk Usuń zaznaczony po prawej.

Spis kontrolek i paneli (UI)
Okno i siatka główna
Window– główne okno aplikacji.Grid(główna) – układ strony, 4 wiersze:Auto, Auto, *, Autoi 2 kolumny:*, *.
Użyte do rozmieszczenia: GroupBox (formularz), pasek filtrów, DataGrid, pasek akcji.
Sekcja „Nowy wydatek”
GroupBox„Nowy wydatek” – obramowanie i tytuł sekcji.Grid(wewnątrz GroupBoxa) – 2 wiersze (Auto) i 4 kolumny (2*, 2*, *, *) dla równych bloków pól.StackPanel×4 – każdy dla jednego pola z etykietą:TextBlock– etykiety: „Nazwa”, „Kategoria”, „Kwota (PLN)”, „Data”.TextBox x:Name="tbNazwa"– bindingText="{Binding Nowy.Nazwa}", walidacja przezIDataErrorInfo, ToolTip z(Validation.Errors).ComboBox x:Name="cbKategoria"–ItemsSource="{Binding Kategorie}",SelectedItem="{Binding Nowy.Kategoria}".TextBox x:Name="tbKwota"–Text="{Binding Nowy.Kwota}"(walidacja > 0).DatePicker x:Name="dpData"–SelectedDate="{Binding Nowy.Data}".
Button x:Name="btnDodaj"–Command="{Binding DodajCmd}", aktywność sterowana przezCanExecute(u nas podbijane przezNowy.PropertyChanged).
Pasek filtrów i sumy
StackPanel(poziomy) – zawiera:TextBlock„Rok”,TextBox x:Name="tbRok"–Text="{Binding Rok}".TextBlock„Miesiąc (1-12)”,TextBox x:Name="tbMiesiac"–Text="{Binding Miesiac}".TextBlock„Suma miesiąca:”,TextBlock x:Name="lblSuma"–Text="{Binding SumaMiesiaca, StringFormat={}{0:F2} PLN}".Button x:Name="btnZapisz"–Command="{Binding ZapiszCmd}".Button x:Name="btnWczytaj"–Command="{Binding WczytajCmd}".
Lista wydatków
DataGrid x:Name="dgWydatki"–ItemsSource="{Binding WidokWydatkow}",SelectedItem="{Binding Zaznaczony}", kolumny:DataGridTextColumn Header="Nazwa"–Binding="{Binding Nazwa}".DataGridTextColumn Header="Kategoria"–Binding="{Binding Kategoria}".DataGridTextColumn Header="Kwota"–Binding="{Binding Kwota, StringFormat={}{0:F2}}".DataGridTextColumn Header="Data"–Binding="{Binding Data, StringFormat={}{0:yyyy-MM-dd}}".
Pasek akcji dolny
StackPanel(poziomy, prawa krawędź)Button x:Name="btnUsun"–Content="Usuń zaznaczony",Command="{Binding UsunCmd}".
Dodatkowe elementy „niewizualne”, ale istotne dla UI
- ToolTip na polach tekstowych – pokazuje pierwszy błąd walidacji z
(Validation.Errors)[0].ErrorContent. - ICollectionView z
Filter– to nie kontrolka, ale mechanizm, który steruje tym, co widzi DataGrid (filtrowanie poRok/Miesiac). - MessageBox – potwierdzenia/komunikaty przy zapisie i odczycie (środowisko WPF).
5. Algorytmy (pseudokod)
5.1. Dodawanie wydatku
CanDodaj():
zwróć TRUE tylko, jeśli:
Nazwa != "" i długość <= 50
Kategoria wybrana
Kwota > 0
Data ustawiona
Dodaj():
jeśli CanDodaj():
kopia = Wydatek(Nazwa, Kategoria, Kwota, Data)
Wydatki.Add(kopia)
Nowy = Wydatek(Kategoria = kopia.Kategoria, Data = dzisiaj) // reset formularza
WidokWydatkow.Refresh()
SumaMiesiaca = przelicz()
5.2. Filtrowanie i suma
FiltrMiesiaca(wydatek):
zwróć (wydatek.Data.Year == Rok) i (wydatek.Data.Month == Miesiac)
przelicz():
suma = 0
dla każdego w w Wydatki:
jeśli w.Data.Year == Rok i w.Data.Month == Miesiac:
suma += w.Kwota
zwróć suma
5.3. Usuwanie i zapis/odczyt
Usuń():
jeśli Zaznaczony != null:
Wydatki.Remove(Zaznaczony)
WidokWydatkow.Refresh()
SumaMiesiaca = przelicz()
Zapisz():
ścieżka = AppData\DomowyBudzetWpf\wydatki.json
utwórz katalog jeśli nie istnieje
json = serializuj(Wydatki)
zapisz json do pliku
Wczytaj():
jeśli plik istnieje:
lista = deserializuj(json)
Wydatki.Clear(); Wydatki.AddRange(lista)
WidokWydatkow.Refresh()
SumaMiesiaca = przelicz()
6. Kroki wykonania (skrót dla ucznia)
- Utwórz WPF App „DomowyBudzetWpf” (.NET 6/8).
- Dodaj foldery i pliki zgodnie z pkt 3.
- W
MainWindow.xamlzbuduj układ. - W
dane.cszdefiniuj modelWydatekz atrybutami walidacyjnymi iIDataErrorInfo. - W
WalidacjaBudzet.csdodaj helper walidacji iRelayCommand. - W
LogikaBudzet.cszaimplementuj:ObservableCollection<Wydatek>, formularzNowy, filtryRok,Miesiac,SumaMiesiaca,ICollectionView.Filter, komendyDodaj/Usuń/Zapisz/Wczytaj, zapis/odczyt JSON, oraz subskrypcjęNowy.PropertyChanged(żeby Dodaj się uaktywniał). - W
MainWindow.xaml.csustawDataContext = new LogikaBudzet(); - Uruchom i przetestuj.
7. Testy (co sprawdza egzaminator)
- Walidacja blokuje Dodaj przy błędnych/ pustych danych.
- Po zmianie Rok/Miesiąc lista i Suma zmieniają się natychmiast.
- Dodanie poprawnego wpisu pojawia się w liście; suma rośnie.
- „Usuń zaznaczony” usuwa wpis i poprawnie przelicza sumę.
- „Zapisz” tworzy plik JSON, „Wczytaj” odtwarza stan.
8. Kryteria oceniania (30 pkt)
- Model + walidacja DataAnnotations + IDataErrorInfo – 6 pkt
- Poprawne bindingi (formularz, lista, suma, filtry) – 8 pkt
- Komendy i logika Dodaj/Usuń – 6 pkt
- Filtr i natychmiastowe odświeżanie widoku + poprawna suma – 6 pkt
- Zapis/odczyt JSON + poprawna ścieżka AppData – 4 pkt
Błędy krytyczne: brak walidacji, nieaktywujący się Dodaj, błędna suma, niedziałający filtr, uszkodzony zapis/odczyt.
9. Co oddać
- Projekt Visual Studio w folderze
DomowyBudzetWpf(spakowany .zip). - Plik
wydatki.json(jeśli wygenerowany) w AppData – nie jest wymagany w archiwum. - Krótkie „readme.txt” (opcjonalnie): jak uruchomić, gdzie zapisuje dane.

