Sito Eratostenesa — WPF (UI) + osobna logika

1. Założenia i struktura

Robimy 1 projekt WPF. UI jest w MainWindow.xaml, a algorytm w osobnej klasie Logika.cs w folderze LogikaSita.

SitoWpf (WPF App)
 ├─ MainWindow.xaml
 ├─ MainWindow.xaml.cs
 └─ LogikaSita
     └─ Logika.cs

2. Tworzenie projektu (Visual Studio 2022)

  1. File → New → Project → WPF App (.NET)
    Nazwa: SitoWpf (jeśli wybierzesz inną, pamiętaj o spójności namespace).
  2. W Solution Explorer: prawy klik na projekt → Add → New FolderLogikaSita.
  3. Prawy klik na folder LogikaSita → Add → Class → nazwa: Logika.cs.

3. Pliki

3.1 LogikaSita/Logika.cs — czysta logika

using System;
using System.Collections.Generic;

namespace SitoWpf.LogikaSita
{
    /// <summary>
    /// Najprostsze Sito Eratostenesa:
    /// Zwraca listę liczb pierwszych ≤ 'zakres'.
    /// </summary>
    public static class Logika
    {
        public static List<int> SitoEratostenesa(int zakres)
        {
            var wynik = new List<int>();

            if (zakres < 2)
                return wynik;

            int dokad = (int)Math.Floor(Math.Sqrt(zakres));

            // Tablica: indeks = liczba; 0 = skreślona, !=0 = liczba kandydująca
            int[] tab = new int[zakres + 1];

            // Inicjalizacja (1..zakres)
            for (int i = 1; i <= zakres; i++)
                tab[i] = i;

            // Sito
            for (int i = 2; i <= dokad; i++)
            {
                if (tab[i] != 0)
                {
                    int j = i + i;
                    while (j <= zakres)
                    {
                        tab[j] = 0;
                        j += i;
                    }
                }
            }

            // Zbierz liczby pierwsze (niezerowe od 2)
            for (int i = 2; i <= zakres; i++)
                if (tab[i] != 0)
                    wynik.Add(tab[i]);

            return wynik;
        }
    }
}

3.2 MainWindow.xaml — UI (kontrolki z nazwami!)

<Window x:Class="SitoWpf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Sito Eratostenesa (WPF)" Height="420" Width="640">
    <Grid Margin="16" RowDefinitions="Auto,Auto,*,Auto" RowSpacing="8">

        <!-- Tytuł -->
        <TextBlock Text="Sito Eratostenesa"
                   FontSize="24" FontWeight="Bold"
                   HorizontalAlignment="Center" />

        <!-- Wejście i przycisk -->
        <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,8,0,0">
            <TextBox x:Name="ZakresTextBox"
                     Width="180"
                     VerticalAlignment="Center"
                     Margin="0,0,8,0"
                     ToolTip="Podaj górny zakres, np. 100"
                     PlaceholderText="Podaj zakres" />
            <!-- Jeśli PlaceholderText nie działa w Twojej wersji WPF, usuń tę właściwość. -->
            <Button Content="Oblicz"
                    Padding="12,6"
                    Click="Oblicz_Click" />
        </StackPanel>

        <!-- Wynik: tekst wielowierszowy w ScrollViewer -->
        <ScrollViewer Grid.Row="2" Margin="0,8,0,8" VerticalScrollBarVisibility="Auto">
            <TextBox x:Name="WynikTextBox"
                     TextWrapping="Wrap"
                     AcceptsReturn="True"
                     IsReadOnly="True"
                     VerticalScrollBarVisibility="Auto"
                     FontFamily="Consolas"
                     FontSize="14"/>
        </ScrollViewer>

        <!-- Informacja pomocnicza -->
        <TextBlock x:Name="InfoTextBlock"
                   Grid.Row="3"
                   Foreground="Gray"
                   Text=""
                   TextWrapping="Wrap"/>
    </Grid>
</Window>

Uwaga: w „gołym” WPF PlaceholderText w TextBox nie jest standardową właściwością. Jeśli VS ją podkreśli, po prostu ją usuń. Dodałem ją jako miłą podpowiedź — ale WPF jej nie ma natywnie.

Zatem bez tej linii (jeśli potrzeba):

<!-- usuń tę linię, jeśli masz błąd -->
PlaceholderText="Podaj zakres"

3.3 MainWindow.xaml.cs — code-behind (klej UI ↔ logika)

using System;
using System.Linq;
using System.Windows;
using SitoWpf.LogikaSita; // używamy naszej klasy Logika

namespace SitoWpf
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent(); // tworzy kontrolki z XAML i łączy je z tą klasą
        }

        private void Oblicz_Click(object sender, RoutedEventArgs e)
        {
            // 1) Parsowanie i walidacja wejścia
            if (!int.TryParse(ZakresTextBox.Text?.Trim(), out int zakres) || zakres < 2)
            {
                InfoTextBlock.Text = "Podaj poprawny zakres (liczba całkowita ≥ 2).";
                WynikTextBox.Text = string.Empty;
                return;
            }

            try
            {
                // 2) Wywołanie logiki
                var primes = Logika.SitoEratostenesa(zakres);

                // 3) Prezentacja wyników
                InfoTextBlock.Text = $"Liczb pierwszych ≤ {zakres}: {primes.Count}";
                WynikTextBox.Text = string.Join(", ", primes);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Błąd", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
    }
}

4. Co tu się dzieje (krótko dla ucznia)

  • Logika.cs: czysty algorytm (bez UI), zwraca List<int> z liczbami pierwszymi.
  • MainWindow.xaml: wygląd okna, pola i przycisk. Nazwy kontrolek (x:Name) to: ZakresTextBox, WynikTextBox, InfoTextBlock.
  • MainWindow.xaml.cs: metoda Oblicz_Click czyta zakres z TextBox, woła Logika.SitoEratostenesa(zakres) i wynik wypisuje do TextBox.

5. Najczęstsze błędy i szybkie naprawy

  1. „Nazwa ‘ZakresTextBox’/… nie istnieje w bieżącym kontekście”
    • Sprawdź, czy w XAML dokładnie masz x:Name="ZakresTextBox" itd.
    • Sprawdź nagłówek okna: x:Class="SitoWpf.MainWindow" — i w .cs namespace + klasa muszą być identyczne (namespace SitoWpf { public partial class MainWindow : Window … }).
    • Zapisz pliki, zbuduj projekt (Build), czasem VS generuje klasy dopiero po Build.
    • Upewnij się, że MainWindow.xaml ma Build Action = Page (w Properties).
  2. PlaceholderText błąd
    • W czystym WPF usuń PlaceholderText, bo nie jest natywny (to cecha UWP/WinUI).
  3. Polskie przecinki w liczbach
    • Używamy int.TryParse, więc tu bez znaczenia. Przy double warto użyć CultureInfo.

6. Co można łatwo rozbudować

  • Zamiast jednego TextBox na wynik użyj ListBox i ItemsSource = primes.
  • Dodaj czas wykonania (Stopwatch) dla większych zakresów.
  • Zabezpiecz zakres (np. maks. 1 000 000) i pokaż komunikat.