Modele/Ksiazki.cs
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Biblioteka.Modele
{
/// Reprezentuje pojedynczą książkę w prostej aplikacji bibliotecznej.
/// Zawiera właściwości do bezpośredniego bindowania w UI (bez konwerterów).
public class Ksiazka : INotifyPropertyChanged
{
private string _tytul = "";
private string _autor = "";
private StatusKsiazki _status = StatusKsiazki.Dostepna;
private DateTime? _dataZwrotu;
/// Tytuł książki.
public string Tytul { get => _tytul; set { _tytul = value; OnPropertyChanged(); } }
/// Autor książki.
public string Autor { get => _autor; set { _autor = value; OnPropertyChanged(); } }
///Status dostępności książki: Dostępna lub Wypożyczona.
public StatusKsiazki Status
{
get => _status;
set { _status = value; OnPropertyChanged(); OdswiezPolaWyliczane(); }
}
/// Data planowanego zwrotu (gdy książka jest wypożyczona).
public DateTime? DataZwrotu
{
get => _dataZwrotu;
set { _dataZwrotu = value; OnPropertyChanged(); OdswiezPolaWyliczane(); }
}
// ------- Właściwości „pod UI” -------
/// Gotowy opis statusu do wyświetlenia w interfejsie,
/// np. "Dostępna" albo "Wypożyczona do 25.04.2024".
public string StatusOpis =>
Status == StatusKsiazki.Dostepna ? "Dostępna"
: $"Wypożyczona do {DataZwrotu:dd.MM.yyyy}";
/// Tekst przycisku akcji wyświetlany w liście (Wypożycz/Zwróć).
public string AkcjaTekst =>
Status == StatusKsiazki.Dostepna ? "Wypożycz" : "Zwróć";
/// Ręcznie powiadamia UI, że pola wyliczane (StatusOpis/AkcjaTekst)
/// zmieniły się po modyfikacji Statusu lub DatyZwrotu.
public void OdswiezPolaWyliczane()
{
OnPropertyChanged(nameof(StatusOpis));
OnPropertyChanged(nameof(AkcjaTekst));
}
public event PropertyChangedEventHandler? PropertyChanged;
/// Powiadamia mechanizm bindowania o zmianie wskazanej właściwości.
private void OnPropertyChanged([CallerMemberName] string? name = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
/// Enum statusu książki.
public enum StatusKsiazki { Dostepna, Wypozyczona }
}
Walidacja/WalidatorKsiazki.cs
using System.Collections.Generic;
using Biblioteka.Modele;
namespace Biblioteka.Walidacja
{
/// Zapewnia podstawową walidację danych książki.
/// Prosto: sprawdzamy tytuł, autora oraz datę zwrotu przy statusie "Wypożyczona".
public static class WalidatorKsiazki
{
/// Zwraca listę komunikatów o błędach. Pusta lista oznacza brak błędów.
public static List<string> Sprawdz(Ksiazka k)
{
var bledy = new List<string>();
if (k == null) { bledy.Add("Brak obiektu książki."); return bledy; }
if (string.IsNullOrWhiteSpace(k.Tytul))
bledy.Add("Podaj tytuł.");
if (string.IsNullOrWhiteSpace(k.Autor))
bledy.Add("Podaj autora.");
if (k.Status == StatusKsiazki.Wypozyczona && k.DataZwrotu == null)
bledy.Add("Dla statusu 'Wypożyczona' ustaw datę zwrotu.");
return bledy;
}
}
}
Logika/BibliotekaSeris.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Biblioteka.Modele;
using Biblioteka.Walidacja;
namespace Biblioteka.Logika
{
/// Prosty serwis do zarządzania kolekcją książek w pamięci (bez bazy danych).
/// Używa ObservableCollection, by UI reagował na zmiany listy.
public class BibliotekaSerwis
{
/// Kolekcja książek widoczna dla UI.
public ObservableCollection<Ksiazka> Ksiazki { get; } = new();
/// Tworzy serwis z przykładowymi danymi startowymi.
public BibliotekaSerwis()
{
Ksiazki.Add(new Ksiazka { Tytul = "The Great Gatsby", Autor = "F. Scott Fitzgerald" });
Ksiazki.Add(new Ksiazka
{
Tytul = "Dune",
Autor = "Frank Herbert",
Status = StatusKsiazki.Wypozyczona,
DataZwrotu = DateTime.Today.AddDays(10)
});
Ksiazki.Add(new Ksiazka { Tytul = "Hobbit", Autor = "J.R.R. Tolkien" });
Ksiazki.Add(new Ksiazka
{
Tytul = "1984",
Autor = "George Orwell",
Status = StatusKsiazki.Wypozyczona,
DataZwrotu = DateTime.Today.AddDays(5)
});
}
/// Dodaje nową książkę po walidacji. Zwraca krotkę: czy_ok oraz lista_błędów.
public (bool ok, List<string> bledy) DodajKsiazke(Ksiazka nowa)
{
var b = WalidatorKsiazki.Sprawdz(nowa);
if (b.Count > 0) return (false, b);
Ksiazki.Add(nowa);
return (true, b);
}
/// Oznacza książkę jako wypożyczoną do przekazanej daty.
public bool WypozyczKsiazke(Ksiazka k, DateTime dataZwrotu)
{
if (k == null || k.Status == StatusKsiazki.Wypozyczona) return false;
k.Status = StatusKsiazki.Wypozyczona;
k.DataZwrotu = dataZwrotu; // INotifyPropertyChanged zaktualizuje UI
return true;
}
///Ustawia status na Dostępna i czyści datę zwrotu.
public bool ZmienStatusNaDostepna(Ksiazka k)
{
if (k == null) return false;
k.Status = StatusKsiazki.Dostepna;
k.DataZwrotu = null;
return true;
}
/// Zwraca książki dopasowane do hasła (w tytule lub autorze). Puste hasło → pełna lista.
public IEnumerable<Ksiazka> Szukaj(string haslo)
{
if (string.IsNullOrWhiteSpace(haslo)) return Ksiazki;
haslo = haslo.Trim().ToLower();
return Ksiazki.Where(k => k.Tytul.ToLower().Contains(haslo) ||
k.Autor.ToLower().Contains(haslo));
}
/// Filtruje po statusie (null → brak filtra).
public IEnumerable<Ksiazka> Filtruj(StatusKsiazki? status)
{
if (status == null) return Ksiazki;
return Ksiazki.Where(k => k.Status == status.Value);
}
}
}
MainWindows.xaml
<Window x:Class="Biblioteka.Wpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:models="clr-namespace:Biblioteka.Modele"
Title="Biblioteka" Height="680" Width="960">
<Grid Margin="16">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Pasek: Szukaj + Filtry -->
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,8">
<TextBox x:Name="txtSzukaj"
Width="320" Height="28"
VerticalContentAlignment="Center"
TextChanged="txtSzukaj_TextChanged"/>
<Button x:Name="btnWszystkie"
Content="Wszystkie książki"
Margin="8,0,0,0"
Click="btnWszystkie_Click"/>
<Button x:Name="btnWypozyczone"
Content="Wypożyczone"
Margin="8,0,0,0"
Click="btnWypozyczone_Click"/>
</StackPanel>
<!-- Lista książek – wyrównana do pełnej szerokości -->
<ListView x:Name="lvKsiazki" Grid.Row="1" SelectionMode="Single"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0,0,0,8"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type models:Ksiazka}">
<Border Padding="12" CornerRadius="8"
BorderBrush="#DDDDDD" BorderThickness="1" Background="#FFFFFF">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel>
<TextBlock Text="{Binding Tytul}" FontSize="18" FontWeight="Bold"/>
<TextBlock Text="{Binding Autor}" Foreground="#555555"/>
<TextBlock Text="{Binding StatusOpis}"/>
</StackPanel>
<Button Grid.Column="1"
Width="110" Height="30"
Content="{Binding AkcjaTekst}"
Click="btnAkcja_Click"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Margin="12,0,0,0"/>
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
MainWindows.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Biblioteka.Logika; // DOPASUJ namespace, jeśli Twój serwis jest gdzie indziej
using Biblioteka.Modele; // DOPASUJ namespace modeli
namespace Biblioteka.Wpf
{
/// Główne okno: wyszukiwanie, filtr statusu, akcja Wypożycz/Zwróć.
public partial class MainWindow : Window
{
private readonly BibliotekaSerwis _serwis = new(); // źródło danych
private IEnumerable<Ksiazka> _widok = Enumerable.Empty<Ksiazka>();
private bool _filtrWypozyczone = false;
public MainWindow()
{
InitializeComponent();
OdswiezWidok();
// WPF: podpinasz ItemsSource (nie DataContext)
lvKsiazki.ItemsSource = _widok;
}
/// Buduje dane do wyświetlenia, biorąc pod uwagę pole Szukaj i filtr statusu.
private void OdswiezWidok()
{
var baza = string.IsNullOrWhiteSpace(txtSzukaj?.Text)
? _serwis.Ksiazki.AsEnumerable()
: _serwis.Szukaj(txtSzukaj.Text);
if (_filtrWypozyczone)
baza = baza.Where(k => k.Status == StatusKsiazki.Wypozyczona);
_widok = baza.ToList();
lvKsiazki.ItemsSource = _widok; // odśwież widok listy
}
// --- Zdarzenia UI ---
private void txtSzukaj_TextChanged(object sender, TextChangedEventArgs e) => OdswiezWidok();
private void btnWszystkie_Click(object sender, RoutedEventArgs e)
{
_filtrWypozyczone = false;
OdswiezWidok();
}
private void btnWypozyczone_Click(object sender, RoutedEventArgs e)
{
_filtrWypozyczone = true;
OdswiezWidok();
}
/// Wspólna akcja dla przycisku „Wypożycz/Zwróć” – decyzja po statusie.
private void btnAkcja_Click(object sender, RoutedEventArgs e)
{
var ksiazka = (sender as FrameworkElement)?.DataContext as Ksiazka;
if (ksiazka == null) return;
if (ksiazka.Status == StatusKsiazki.Dostepna)
{
var data = DateTime.Today.AddDays(14); // proste założenie egzaminowe
_serwis.WypozyczKsiazke(ksiazka, data);
}
else
{
_serwis.ZmienStatusNaDostepna(ksiazka);
}
// Model (INotifyPropertyChanged) zaktualizuje napisy w wierszu;
// ale ponieważ ItemsSource to zwykłe IEnumerable, wywołujemy OdswiezWidok,
// jeśli chcesz też przebudować listę (np. gdy filtr "Wypożyczone" jest aktywny).
if (_filtrWypozyczone) OdswiezWidok();
}
}
}

