Zadanie Biblioteka WPF

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();
        }
    }
}