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)
- File → New → Project → WPF App (.NET)
Nazwa:SitoWpf(jeśli wybierzesz inną, pamiętaj o spójności namespace). - W Solution Explorer: prawy klik na projekt → Add → New Folder →
LogikaSita. - 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
PlaceholderTextwTextBoxnie 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_Clickczyta zakres zTextBox, wołaLogika.SitoEratostenesa(zakres)i wynik wypisuje doTextBox.
5. Najczęstsze błędy i szybkie naprawy
- „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.csnamespace + 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.xamlma Build Action = Page (w Properties).
- Sprawdź, czy w XAML dokładnie masz
- PlaceholderText błąd
- W czystym WPF usuń
PlaceholderText, bo nie jest natywny (to cecha UWP/WinUI).
- W czystym WPF usuń
- Polskie przecinki w liczbach
- Używamy
int.TryParse, więc tu bez znaczenia. Przydoublewarto użyćCultureInfo.
- Używamy
6. Co można łatwo rozbudować
- Zamiast jednego
TextBoxna wynik użyjListBoxiItemsSource = primes. - Dodaj czas wykonania (
Stopwatch) dla większych zakresów. - Zabezpiecz zakres (np. maks. 1 000 000) i pokaż komunikat.

