Przejdź do głównej treści
INF.04-01-24.01-SGStyczeń 2024 · 25 kroków · ok. 76 min · 33 kryteria z klucza

Rozwiązanie krok po kroku: PESEL i dane paszportowe (C# + WPF)

Rozwiązujemy arkusz z numerem PESEL i oknem danych paszportowych w wersji C# + WPF: w konsoli dwie funkcje - jedna odczytuje płeć z przedostatniej cyfry, druga liczy sumę kontrolną z wagami 1, 3, 7, 9 dokładnie według algorytmu z arkusza - a w aplikacji desktopowej okno z polami danych, grupą przycisków opcji koloru oczu i dwoma zdjęciami (twarz i odcisk palca), które podmieniają się po wpisaniu numeru, oraz komunikatem z danymi po kliknięciu „OK”. Do tego dokumentacja funkcji według wzoru z arkusza, zrzuty i dokument egzamin.

Kroki idą zdanie po zdaniu za treścią arkusza - każdy zaczyna się cytatem wymagania, a kod pokazuje dokładnie te linie, które je spełniają. Najpierw piszemy najprostszą wersję, której wymaga klucz, a w etapie „Dobre praktyki” przerabiamy ją na kod z prawdziwych projektów.

Co widać w podglądzie. Wyniki programu konsolowego pochodzą z prawdziwego uruchomienia kodu z danego kroku (.NET 10) z numerem PESEL wpisanym z klawiatury, a każdy wynik sprawdziliśmy niezależnie tym samym algorytmem. Okno aplikacji to symulacja WPF w przeglądarce zbudowana z XAML danego kroku, ze zdjęciami z archiwum materialy.7z; jej zachowanie odpowiada kodowi C# z kroku. Każdy stan okna sprawdziliśmy na prawdziwym WPF.

Arkusz pozwala też na C++, Javę albo Pythona w konsoli i na inne biblioteki okienkowe - ten wariant to jedna z możliwych dróg.

Jak liczą się punkty. Klucz ma 33 kryteria (R.1.1 - R.4.8), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 25 punktów - można stracić 8 kryteriów i nadal zdać. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.

  1. Etap 1: Przygotowanie

    Krok 1 · po tym etapie masz 0 z 33 kryteriów (pkt)

    Krok 1: Folder zdającego, podfoldery i archiwum

    ok. 3 min
    Polecenie z arkusza

    Utwórz folder i nazwij go numerem zdającego. W folderze utwórz podfoldery: konsola, desktopowa, dokumentacja. Do wykonania zadania wykorzystaj znajdujące się na pulpicie archiwum 7-Zip o nazwie materialy.7z zabezpieczone hasłem: p@szporTy%.

    Na pulpicie zakładamy folder o nazwie z numerem PESEL, a w nim konsola, desktopowa i dokumentacja. Archiwum materialy.7z (hasło p@szporTy%) zawiera sześć zdjęć: 000-, 111- i 333-zdjecie.jpg oraz tyle samo -odcisk.jpg - przydadzą się w aplikacji desktopowej.

  2. Etap 2: Aplikacja konsolowa

    Kroki 2-7 · po tym etapie masz 13 z 33 kryteriów (pkt)

    Krok 2: Projekt konsola w C#

    ok. 3 min
    Polecenie z arkusza

    Zastosowany obiektowy język programowania zgodny z zainstalowanym na stanowisku egzaminacyjnym: C++ lub C#, lub Java, lub Python.

    Wybieramy C#. W Visual Studio: Utwórz nowy projekt → Aplikacja konsolowa, nazwa konsola; w terminalu: dotnet new console -n konsola. W Program.cs zostawiamy klasę Program z pustą metodą Main.

    konsola/Program.cs C# nowy plik
    class Program
    {
        static void Main()
        {
        }
    }
  3. Krok 3: Funkcja CheckGender: płeć z 10. cyfry

    Kryteria: , , ,

    R.2.1 W programie zdefiniowano przynajmniej jedną funkcję, która pobiera jako argument zmienną przechowującą PESEL (typ musi być zgodny) oraz zastosowano instrukcję return dla każdej ścieżki decyzyjnej

    R.2.2 Funkcja sprawdzająca płeć jest typu znakowego, zwraca 'K' gdy 10. cyfra numeru PESEL jest parzysta (0, 2, 4, 6, 8), zwraca 'M', gdy jest nieparzysta (1, 3, 5, 7, 9) (warunki komplementarne - można zastosować samo else)

    R.1.5 Zastosowano typy pasujące do problemu oraz numer PESEL jest przechowywany w zmiennej tekstowej albo tablicy elementów liczbowych lub znakowych. W przypadku porównywania znaku z liczbą stosowano odpowiednią konwersję (np. znak - '0'). W przypadku Python zastosowano jawną konwersję do odpowiednich typów

    R.1.3 Użyto polskie lub angielskie nazewnictwo funkcji. Nazewnictwo jest znaczące

    ok. 3 min
    Polecenie z arkusza

    Informacja o płci osoby zawarta jest na 10. (przedostatniej) pozycji numeru PESEL: cyfry parzyste oznaczają płeć żeńską, nieparzyste - męską. Sprawdzanie płci należy zaimplementować w osobnej funkcji zwracającej typ znakowy o wartości 'K' dla kobiety oraz 'M' dla mężczyzny. Parametrem wejściowym funkcji jest zmienna przechowująca numer PESEL.

    PESEL trzymamy w zmiennej tekstowej string - to dozwolone w arkuszu i wygodne, bo numer może zaczynać się od zera. Dziesiąta cyfra ma indeks 9 (liczymy od zera). pesel[9] to znak, np. '9'; odjęcie znaku '0' zamienia go na liczbę 9 - kody cyfr w tablicy znaków są kolejne (R.1.5). Parzystość sprawdza reszta z dzielenia przez 2. Funkcja zwraca typ char i ma return w obu gałęziach (R.2.1, R.2.2).

    Typowe błędy

    pesel[10] zamiast pesel[9] - to jedenasta cyfra (kontrolna), nie przedostatnia.

    konsola/Program.cs C# zmienione: 13 linii
    class Program
    {
        static char CheckGender(string pesel)
        {
            int genderDigit = pesel[9] - '0';
            if (genderDigit % 2 == 0)
            {
                return 'K';
            }
            else
            {
                return 'M';
            }
        }
    
        static void Main()
        {
        }
    }
  4. Krok 4: Suma iloczynów cyfr i wag

    Kryteria: , ,

    R.2.4 Wykonano pierwszy etap liczenia sumy kontrolnej: dla pierwszych 10 cyfr numeru PESEL zostały obliczone ich iloczyny z wagami (1, 3, 7, 9, 1, 3, 7 ,9 ,1, 3)

    R.2.5 Wykonano 2. etap liczenia sumy kontrolnej: sumowanie obliczonych 10 iloczynów (należy sprawdzić jedynie sumowanie nawet jeśli wagi te byłyby błędne)

    R.1.4 Użyto polskie lub angielskie nazewnictwo zmiennych. Nazewnictwo jest znaczące. Wyjątkami od reguły są zmienne bufor, tmp, iteratory pętli, oraz zmienne wynikające z algorytmu: S, M, R. Kryterium nie jest spełnione tylko wtedy, gdy nazwy zmiennych nic nie znaczą, np. x, tab, tablica, foo

    ok. 3 min
    Polecenie z arkusza

    Dla kolejnych 10 cyfr numeru PESEL oblicz iloczyn każdej cyfry i jej wagi na podstawie tabeli: wagi 1 3 7 9 1 3 7 9 1 3. Wszystkie iloczyny zsumuj ze sobą i zapisz w zmiennej S.

    Wagi z tabeli trzymamy w tablicy weights - indeks wagi odpowiada indeksowi cyfry. Pętla przechodzi przez pierwsze dziesięć cyfr (indeksy 0-9), mnoży cyfrę przez wagę i dodaje do sumy S (nazwa z algorytmu - klucz dopuszcza S, M i R, R.1.4). Funkcja ma już typ bool; tymczasowo zwraca false - dokończymy ją w następnym kroku.

    konsola/Program.cs C# zmienione: 11 linii
    class Program
    {
        static char CheckGender(string pesel)
        {
            int genderDigit = pesel[9] - '0';
            if (genderDigit % 2 == 0)
            {
                return 'K';
            }
            else
            {
                return 'M';
            }
        }
    
        static bool CheckControlSum(string pesel)
        {
            int[] weights = { 1, 3, 7, 9, 1, 3, 7, 9, 1, 3 };
            int S = 0;
            for (int i = 0; i < 10; i++)
            {
                S += (pesel[i] - '0') * weights[i];
            }
            return false;
        }
    
        static void Main()
        {
        }
    }
  5. Krok 5: M, R i porównanie z cyfrą kontrolną

    Kryteria: , ,

    R.2.3 Funkcja sprawdzająca sumę kontrolną jest typu logicznego, zwraca true gdy obliczona suma kontrolna jest równa 11. cyfrze PESEL lub false w przeciwnym wypadku

    R.2.6 Wykonano 3. i 4. etap liczenia sumy kontrolnej: obliczono wynik M = S % 10 oraz gdy M>0 to R=10-M; gdy M==0 to R=0 Mogą być zastosowane inne nazwy zmiennych niż M, S, R

    R.1.2 Kod zapisano z wcięciami dla zagłębień bloków

    ok. 3 min
    Polecenie z arkusza

    Wykonaj operację modulo 10 na sumie S i zapisz w zmiennej M. Gdy wartość zmiennej M jest równa 0, to zmiennej R przypisz wartość 0. W przeciwnym przypadku zmiennej R przypisz wartość różnicy 10 i M (R=10-M). Zmienna R stanowi sumę kontrolną numeru PESEL i musi być równa jedenastej cyfrze numeru PESEL.

    Kroki 3-5 algorytmu jeden do jednego: M = S % 10, potem R zależnie od M. Wynik funkcji to porównanie R == pesel[10] - '0' - samo w sobie jest wartością true albo false, więc nie potrzebujemy osobnego if (R.2.3, R.2.6).

    Przykład z arkusza 55030101193: suma iloczynów 87, M = 7, R = 3 - zgadza się z ostatnią cyfrą 3.

    konsola/Program.cs C# zmienione: 11 linii
    class Program
    {
        static char CheckGender(string pesel)
        {
            int genderDigit = pesel[9] - '0';
            if (genderDigit % 2 == 0)
            {
                return 'K';
            }
            else
            {
                return 'M';
            }
        }
    
        static bool CheckControlSum(string pesel)
        {
            int[] weights = { 1, 3, 7, 9, 1, 3, 7, 9, 1, 3 };
            int S = 0;
            for (int i = 0; i < 10; i++)
            {
                S += (pesel[i] - '0') * weights[i];
            }
            int M = S % 10;
            int R;
            if (M == 0)
            {
                R = 0;
            }
            else
            {
                R = 10 - M;
            }
            return R == pesel[10] - '0';
        }
    
        static void Main()
        {
        }
    }
  6. Krok 6: Program główny: wczytanie, płeć i suma kontrolna

    Kryteria: , ,

    R.2.7 W programie głównym wywołano co najmniej jedną funkcję dla numeru PESEL wczytanego z klawiatury

    R.1.7 Program podejmuje komunikację z użytkownikiem: monit o wprowadzenie danych jest znaczący lub wyświetlenie danych opatrzono znaczącym komunikatem, wyświetlana jest płeć w postaci całego słowa "Kobieta" lub "Mężczyzna"

    R.1.1 Kod źródłowy zapisano w sposób czytelny: instrukcje w osobnych liniach, stosowane spacje pomiędzy operatorami, konsekwentnie stosowana wybrana konwencja dla nawiasów klamrowych instrukcji blokowej

    ok. 4 min
    Polecenie z arkusza

    Zmienna ta jest zainicjowana numerem PESEL zdającego lub w przypadku jego braku numerem 55030101193. Program główny testuje działanie funkcji i zawiera następujące operacje wejścia – wyjścia: wczytanie z klawiatury numeru PESEL, wypisanie płci (ustalonej przez funkcję) w postaci napisu: „Kobieta” lub „Mężczyzna”, wypisanie informacji o zgodności lub niezgodności sumy kontrolnej.

    Zmienną inicjujemy numerem z arkusza (na egzaminie - własnym PESEL-em), a potem nadpisujemy tym, co wpisze użytkownik. Funkcja płci zwraca znak, więc w Main zamieniamy go na całe słowo - klucz wymaga „Kobieta” albo „Mężczyzna”, nie samej litery (R.1.7).

    Podgląd to trzy prawdziwe uruchomienia: 55030101193 (mężczyzna, suma zgodna), 92071314764 (kobieta, suma zgodna) i 55030101194 (zmieniona ostatnia cyfra - suma niezgodna).

    konsola/Program.cs C# zmienione: 21 linii
    class Program
    {
        static char CheckGender(string pesel)
        {
            int genderDigit = pesel[9] - '0';
            if (genderDigit % 2 == 0)
            {
                return 'K';
            }
            else
            {
                return 'M';
            }
        }
    
        static bool CheckControlSum(string pesel)
        {
            int[] weights = { 1, 3, 7, 9, 1, 3, 7, 9, 1, 3 };
            int S = 0;
            for (int i = 0; i < 10; i++)
            {
                S += (pesel[i] - '0') * weights[i];
            }
            int M = S % 10;
            int R;
            if (M == 0)
            {
                R = 0;
            }
            else
            {
                R = 10 - M;
            }
            return R == pesel[10] - '0';
        }
    
        static void Main()
        {
            string pesel = "55030101193";
            Console.Write("Podaj numer PESEL: ");
            pesel = Console.ReadLine();
    
            if (CheckGender(pesel) == 'K')
            {
                Console.WriteLine("Płeć: Kobieta");
            }
            else
            {
                Console.WriteLine("Płeć: Mężczyzna");
            }
    
            if (CheckControlSum(pesel))
            {
                Console.WriteLine("Suma kontrolna jest zgodna");
            }
            else
            {
                Console.WriteLine("Suma kontrolna jest niezgodna");
            }
        }
    }
    Wynik programu po tym kroku
    > konsola.exe
    Podaj numer PESEL: 55030101193
    Płeć: Mężczyzna
    Suma kontrolna jest zgodna
    
    > konsola.exe
    Podaj numer PESEL: 92071314764
    Płeć: Kobieta
    Suma kontrolna jest zgodna
    
    > konsola.exe
    Podaj numer PESEL: 55030101194
    Płeć: Mężczyzna
    Suma kontrolna jest niezgodna
  7. Krok 7: Folder konsola: archiwum, źródło i plik wykonywalny

    ok. 2 min
    Polecenie z arkusza

    Kod aplikacji przygotuj do nagrania na płytę. W folderze konsola zapisz archiwum całego projektu o nazwie konsola.zip, plik z kodem źródłowym programu oraz plik uruchomieniowy, jeżeli istnieje.

    Folder projektu pakujemy do konsola.zip, obok kopiujemy Program.cs i konsola.exe z bin\Debug\net.... Archiwum robimy na końcu, po dopisaniu komentarza dokumentującego.

    Wynik programu bez zmian - taki jak po kroku 6.

  8. Etap 3: Aplikacja desktopowa

    Kroki 8-18 · po tym etapie masz 23 z 33 kryteriów (pkt)

    Krok 8: Nowy projekt WPF desktopowa

    ok. 3 min
    Polecenie z arkusza

    Za pomocą dostępnego na stanowisku egzaminacyjnym środowiska programistycznego wykonaj aplikację desktopową do wprowadzania danych paszportowych.

    W Visual Studio: Utwórz nowy projekt → Aplikacja WPF, nazwa desktopowa. Wygląd okna piszemy w MainWindow.xaml, a logikę w MainWindow.xaml.cs. Tym razem zmienimy też plik projektu desktopowa.csproj - dołączymy do niego zdjęcia.

    desktopowa/MainWindow.xaml XAML nowy plik
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Grid>
    
        </Grid>
    </Window>
    desktopowa/MainWindow.xaml.cs C# nowy plik
    using System.Windows;
    
    namespace desktopowa;
    
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
    desktopowa/desktopowa.csproj Projekt C# nowy plik
    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>net10.0-windows</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
        <UseWPF>true</UseWPF>
      </PropertyGroup>
    
    </Project>
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  9. Krok 9: Tytuł, rozmiar i tło okna

    Kryteria: ,

    R.3.1 Dla okna aplikacji nadano nazwę "Wprowadzenie danych do paszportu. Wykonał: " wraz z numerem zdającego oraz umieszczono w oknie trzy pola edycyjne, trzy pola opcji, dwa obrazy i przycisk

    R.3.2 Nadano dla okna tło koloru CadetBlue (#5F9EA0) oraz dla pól edycyjnych i przycisku tło koloru Azure (#F0FFFF)

    ok. 2 min
    Polecenie z arkusza

    Okno o nazwie „Wprowadzenie danych do paszportu. Wykonał: ” następnie wstawiony numer zdającego. Okno ma tło koloru CadetBlue (#5F9EA0).

    Title z treścią z arkusza - na egzaminie po „Wykonał:” wpisujemy numer PESEL, tu stoi Bartosz Bryniarski. Rozmiar 750 × 330 jak na obrazie 1, tło kodem z arkusza (CadetBlue działa tak samo).

    desktopowa/MainWindow.xaml XAML zmienione: 2 linie
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="Wprowadzenie danych do paszportu. Wykonał: Bartosz Bryniarski" Height="330" Width="750"
            Background="#5F9EA0">
        <Grid>
    
        </Grid>
    </Window>
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  10. Krok 10: Dwie kolumny i pole Numer

    Kryteria: ,

    R.3.1 Dla okna aplikacji nadano nazwę "Wprowadzenie danych do paszportu. Wykonał: " wraz z numerem zdającego oraz umieszczono w oknie trzy pola edycyjne, trzy pola opcji, dwa obrazy i przycisk

    R.3.2 Nadano dla okna tło koloru CadetBlue (#5F9EA0) oraz dla pól edycyjnych i przycisku tło koloru Azure (#F0FFFF)

    ok. 3 min
    Polecenie z arkusza

    Kontrolki rozmieszczone zgodnie z obrazem 1: Pole edycyjne poprzedzone etykietą o treści „Numer”. Pola edycyjne i przycisk mają tło koloru Azure (#F0FFFF).

    Główny Grid ma dwie kolumny: lewą (330 px) na pola i opcje, prawą na zdjęcia i przycisk. W lewej kolumnie StackPanel układa jeden pod drugim mniejszy Grid z etykietami i polami (kolumna etykiet 110 px) i - później - grupę kolorów oczu. Pole numberTextBox dostaje tło Azure (#F0FFFF).

    desktopowa/MainWindow.xaml XAML zmienione: 20 linii
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="Wprowadzenie danych do paszportu. Wykonał: Bartosz Bryniarski" Height="330" Width="750"
            Background="#5F9EA0">
        <Grid Margin="20">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="330" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <StackPanel>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="110" />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Label Content="Numer" Margin="0,3" />
                    <TextBox x:Name="numberTextBox" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF" />
                </Grid>
            </StackPanel>
        </Grid>
    </Window>
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  11. Krok 11: Pola Imię i Nazwisko

    Kryteria: ,

    R.3.1 Dla okna aplikacji nadano nazwę "Wprowadzenie danych do paszportu. Wykonał: " wraz z numerem zdającego oraz umieszczono w oknie trzy pola edycyjne, trzy pola opcji, dwa obrazy i przycisk

    R.3.2 Nadano dla okna tło koloru CadetBlue (#5F9EA0) oraz dla pól edycyjnych i przycisku tło koloru Azure (#F0FFFF)

    ok. 2 min
    Polecenie z arkusza

    Pole edycyjne poprzedzone etykietą o treści „Imię”. Pole edycyjne poprzedzone etykietą o treści „Nazwisko”.

    Dwa kolejne wiersze siatki, każdy z etykietą i polem o własnej nazwie (firstNameTextBox, lastNameTextBox), z tym samym tłem Azure.

    desktopowa/MainWindow.xaml XAML zmienione: 4 linie
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="Wprowadzenie danych do paszportu. Wykonał: Bartosz Bryniarski" Height="330" Width="750"
            Background="#5F9EA0">
        <Grid Margin="20">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="330" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <StackPanel>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="110" />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Label Content="Numer" Margin="0,3" />
                    <TextBox x:Name="numberTextBox" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF" />
                    <Label Grid.Row="1" Content="Imię" Margin="0,3" />
                    <TextBox x:Name="firstNameTextBox" Grid.Row="1" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF" />
                    <Label Grid.Row="2" Content="Nazwisko" Margin="0,3" />
                    <TextBox x:Name="lastNameTextBox" Grid.Row="2" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF" />
                </Grid>
            </StackPanel>
        </Grid>
    </Window>
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  12. Krok 12: Grupa Kolor oczu z przyciskami opcji

    Kryteria: ,

    R.3.1 Dla okna aplikacji nadano nazwę "Wprowadzenie danych do paszportu. Wykonał: " wraz z numerem zdającego oraz umieszczono w oknie trzy pola edycyjne, trzy pola opcji, dwa obrazy i przycisk

    R.3.3 Pola opcji zgrupowano: jednocześnie można wybrać tylko jedno pole, w stanie początkowym wybrane jest pole "niebieskie"

    ok. 3 min
    Polecenie z arkusza

    Grupa „Kolor oczu” zawierająca trzy pola wyboru: „niebieskie”, „zielone”, „piwne”. Pierwsze pole jest domyślnie zaznaczone. W grupie może być jednocześnie zaznaczone jedno pole.

    „Jedno zaznaczone naraz” to RadioButton (przycisk opcji), nie CheckBox. W WPF przyciski opcji w jednym kontenerze tworzą automatycznie jedną grupę - zaznaczenie jednego odznacza pozostałe (można też jawnie nadać im ten sam GroupName). Ramka z podpisem to GroupBox. IsChecked="True" przy „niebieskie” - stan początkowy (R.3.3). Klikaj opcje w podglądzie.

    Typowe błędy

    Trzy CheckBox pozwalają zaznaczyć kilka kolorów naraz - R.3.3 nie jest spełnione.

    desktopowa/MainWindow.xaml XAML zmienione: 7 linii
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="Wprowadzenie danych do paszportu. Wykonał: Bartosz Bryniarski" Height="330" Width="750"
            Background="#5F9EA0">
        <Grid Margin="20">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="330" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <StackPanel>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="110" />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Label Content="Numer" Margin="0,3" />
                    <TextBox x:Name="numberTextBox" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF" />
                    <Label Grid.Row="1" Content="Imię" Margin="0,3" />
                    <TextBox x:Name="firstNameTextBox" Grid.Row="1" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF" />
                    <Label Grid.Row="2" Content="Nazwisko" Margin="0,3" />
                    <TextBox x:Name="lastNameTextBox" Grid.Row="2" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF" />
                </Grid>
                <GroupBox Header="Kolor oczu" Margin="0,20,0,0">
                    <StackPanel Margin="20,5">
                        <RadioButton x:Name="blueRadioButton" Content="niebieskie" IsChecked="True" Margin="0,5" />
                        <RadioButton x:Name="greenRadioButton" Content="zielone" Margin="0,5" />
                        <RadioButton x:Name="brownRadioButton" Content="piwne" Margin="0,5" />
                    </StackPanel>
                </GroupBox>
            </StackPanel>
        </Grid>
    </Window>
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  13. Krok 13: Miejsce na dwa zdjęcia i przycisk OK

    Kryteria: , ,

    R.3.1 Dla okna aplikacji nadano nazwę "Wprowadzenie danych do paszportu. Wykonał: " wraz z numerem zdającego oraz umieszczono w oknie trzy pola edycyjne, trzy pola opcji, dwa obrazy i przycisk

    R.3.2 Nadano dla okna tło koloru CadetBlue (#5F9EA0) oraz dla pól edycyjnych i przycisku tło koloru Azure (#F0FFFF)

    R.3.5 Obrazom nadano tą samą wysokość

    ok. 3 min
    Polecenie z arkusza

    Przycisk o treści „OK”. Dwa obrazy: 000-zdjecie.jpg oraz 000-odcisk.jpg. Obrazy mają tę samą wysokość. W aplikacji, której okno przedstawiono na obrazie 1 zastosowano wysokość równą 180.

    Prawa kolumna: poziomy StackPanel z dwiema kontrolkami Image o tej samej wysokości 180 (R.3.5) - szerokość dobierze WPF z proporcji zdjęcia. Pod nimi przycisk „OK” z tłem Azure. Obrazy mają nazwy, ale jeszcze nie mają źródła (Source) - wczytamy je w kodzie, bo i tak będziemy je podmieniać po wpisaniu numeru.

    desktopowa/MainWindow.xaml XAML zmienione: 7 linii
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="Wprowadzenie danych do paszportu. Wykonał: Bartosz Bryniarski" Height="330" Width="750"
            Background="#5F9EA0">
        <Grid Margin="20">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="330" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <StackPanel>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="110" />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Label Content="Numer" Margin="0,3" />
                    <TextBox x:Name="numberTextBox" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF" />
                    <Label Grid.Row="1" Content="Imię" Margin="0,3" />
                    <TextBox x:Name="firstNameTextBox" Grid.Row="1" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF" />
                    <Label Grid.Row="2" Content="Nazwisko" Margin="0,3" />
                    <TextBox x:Name="lastNameTextBox" Grid.Row="2" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF" />
                </Grid>
                <GroupBox Header="Kolor oczu" Margin="0,20,0,0">
                    <StackPanel Margin="20,5">
                        <RadioButton x:Name="blueRadioButton" Content="niebieskie" IsChecked="True" Margin="0,5" />
                        <RadioButton x:Name="greenRadioButton" Content="zielone" Margin="0,5" />
                        <RadioButton x:Name="brownRadioButton" Content="piwne" Margin="0,5" />
                    </StackPanel>
                </GroupBox>
            </StackPanel>
            <StackPanel Grid.Column="1">
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                    <Image x:Name="photoImage" Height="180" Margin="10,0" />
                    <Image x:Name="fingerprintImage" Height="180" Margin="10,0" />
                </StackPanel>
                <Button Content="OK" Width="220" Height="35" Margin="0,20,0,0" Background="#F0FFFF" />
            </StackPanel>
        </Grid>
    </Window>
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  14. Krok 14: Zdjęcia w projekcie i wczytanie 000 na starcie

    Kryteria:

    R.3.10 Aplikacja uruchamia się, co udokumentowano zrzutem ekranu, jej układ po uruchomieniu jest zgodny z obrazem 1 w arkuszu egzaminacyjnym. Widoczne są obrazy 000-zdjecie.jpg oraz 000-odcisk.jpg (sprawdzić w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    ok. 5 min
    Polecenie z arkusza

    Dwa obrazy: 000-zdjecie.jpg oraz 000-odcisk.jpg. W przypadku wpisania numeru (np. 444), który nie odpowiada żadnemu plikowi graficznemu, obraz nie jest wyświetlany.

    Sześć zdjęć z archiwum kopiujemy do folderu projektu. W pliku projektu oznaczamy je jako Content z kopiowaniem do folderu wynikowego (w Visual Studio: Właściwości pliku → Akcja kompilacji: Zawartość, Kopiuj do katalogu wyjściowego: Kopiuj, jeśli nowszy) - wtedy leżą obok desktopowa.exe i program znajdzie je po nazwie.

    W kodzie:

    • LoadImage(nazwa) składa pełną ścieżkę z katalogu programu (AppDomain.CurrentDomain.BaseDirectory) i nazwy pliku; gdy pliku nie ma, zwraca null - kontrolka Image z pustym źródłem nic nie pokazuje (R.3.7),
    • LoadImages(numer) ustawia oba obrazy według wzoru <numer>-zdjecie.jpg i <numer>-odcisk.jpg,
    • konstruktor wczytuje zdjęcia 000 - stan początkowy z obrazu 1 (R.3.10).

    BitmapImage? - znak zapytania mówi, że metoda może zwrócić null (projekt ma włączone sprawdzanie wartości null).

    Typowe błędy

    new BitmapImage(new Uri(...)) dla nieistniejącego pliku rzuca wyjątek i zamyka aplikację - dlatego najpierw File.Exists.

    desktopowa/MainWindow.xaml.cs C# zmienione: 19 linii
    using System.IO;
    using System.Windows;
    using System.Windows.Media.Imaging;
    
    namespace desktopowa;
    
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            LoadImages("000");
        }
    
        private void LoadImages(string number)
        {
            photoImage.Source = LoadImage(number + "-zdjecie.jpg");
            fingerprintImage.Source = LoadImage(number + "-odcisk.jpg");
        }
    
        private BitmapImage? LoadImage(string fileName)
        {
            string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
            if (!File.Exists(path))
            {
                return null;
            }
            return new BitmapImage(new Uri(path));
        }
    }
    desktopowa/desktopowa.csproj Projekt C# zmienione: 6 linii
    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>net10.0-windows</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
        <UseWPF>true</UseWPF>
      </PropertyGroup>
    
      <ItemGroup>
        <Content Include="*.jpg">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </Content>
      </ItemGroup>
    
    </Project>
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  15. Krok 15: Podmiana zdjęć po opuszczeniu pola Numer

    Kryteria: , ,

    R.3.4 Po opuszczeniu pola edycyjnego do wpisywania numeru lub po wciśnięciu przycisku wywoływana jest funkcja

    R.3.6 Po wypełnieniu pola edycyjnego do wpisania numeru danymi: 111, 333, 000 są wyświetlone oba obrazy, nazwy plików graficznych zgadzają się z podanym numerem np. dla numeru 111 są to 111-zdjecie.jpg oraz 111-odcisk.jpg (sprawdzić w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    R.3.7 W przeciwnym do R.3.6 przypadku, żaden obraz nie został wyświetlony (sprawdzić w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    ok. 3 min
    Polecenie z arkusza

    Działanie aplikacji po opuszczeniu pola edycyjnego „Numer”: aktualizowane są oba zdjęcia w oknie. Nazwy plików graficznych są utworzone na podstawie wpisanego numeru do pola edycyjnego „Numer”, np. po wpisaniu do pola edycyjnego „333” ustawiona nazwa zdjęcia to 333-zdjecie.jpg.

    „Opuszczenie pola” to zdarzenie LostFocus - zachodzi, gdy kursor przechodzi do innej kontrolki (Tab albo kliknięcie gdzie indziej). W XAML wiążemy je z metodą, a ta wywołuje gotowe LoadImages z tekstem z pola (R.3.4, R.3.6).

    Wpisz w podglądzie 333 i kliknij pole „Imię” - zdjęcia się zmieniają (obraz 3). Numer 111 pokazuje inną parę, a 444 - żadnego zdjęcia.

    Typowe błędy

    Zdarzenie TextChanged podmieniałoby zdjęcia przy każdej wpisanej cyfrze (1, 11, 111) - arkusz mówi o opuszczeniu pola.

    desktopowa/MainWindow.xaml XAML zmienione: 2 linie
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="Wprowadzenie danych do paszportu. Wykonał: Bartosz Bryniarski" Height="330" Width="750"
            Background="#5F9EA0">
        <Grid Margin="20">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="330" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <StackPanel>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="110" />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Label Content="Numer" Margin="0,3" />
                    <TextBox x:Name="numberTextBox" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF"
                             LostFocus="NumberTextBox_LostFocus" />
                    <Label Grid.Row="1" Content="Imię" Margin="0,3" />
                    <TextBox x:Name="firstNameTextBox" Grid.Row="1" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF" />
                    <Label Grid.Row="2" Content="Nazwisko" Margin="0,3" />
                    <TextBox x:Name="lastNameTextBox" Grid.Row="2" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF" />
                </Grid>
                <GroupBox Header="Kolor oczu" Margin="0,20,0,0">
                    <StackPanel Margin="20,5">
                        <RadioButton x:Name="blueRadioButton" Content="niebieskie" IsChecked="True" Margin="0,5" />
                        <RadioButton x:Name="greenRadioButton" Content="zielone" Margin="0,5" />
                        <RadioButton x:Name="brownRadioButton" Content="piwne" Margin="0,5" />
                    </StackPanel>
                </GroupBox>
            </StackPanel>
            <StackPanel Grid.Column="1">
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                    <Image x:Name="photoImage" Height="180" Margin="10,0" />
                    <Image x:Name="fingerprintImage" Height="180" Margin="10,0" />
                </StackPanel>
                <Button Content="OK" Width="220" Height="35" Margin="0,20,0,0" Background="#F0FFFF" />
            </StackPanel>
        </Grid>
    </Window>
    desktopowa/MainWindow.xaml.cs C# zmienione: 5 linii
    using System.IO;
    using System.Windows;
    using System.Windows.Media.Imaging;
    
    namespace desktopowa;
    
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            LoadImages("000");
        }
    
        private void NumberTextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            LoadImages(numberTextBox.Text);
        }
    
        private void LoadImages(string number)
        {
            photoImage.Source = LoadImage(number + "-zdjecie.jpg");
            fingerprintImage.Source = LoadImage(number + "-odcisk.jpg");
        }
    
        private BitmapImage? LoadImage(string fileName)
        {
            string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
            if (!File.Exists(path))
            {
                return null;
            }
            return new BitmapImage(new Uri(path));
        }
    }
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  16. Krok 16: OK: komunikat z danymi i kolorem oczu

    Kryteria: ,

    R.3.4 Po opuszczeniu pola edycyjnego do wpisywania numeru lub po wciśnięciu przycisku wywoływana jest funkcja

    R.3.8 Jeżeli dane zostały wprowadzone do wszystkich pól edycyjnych, po wybraniu przycisku zatwierdzającego, wyświetlane jest okienko komunikatu o treści: „<imie> <nazwisko> kolor oczu <kolor>", gdzie pola w nawiasach <> zostały pobrane z kontrolek (sprawdzić w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    ok. 3 min
    Polecenie z arkusza

    Działanie aplikacji po wybraniu przycisku „OK”: jeżeli dane zostały wprowadzone do wszystkich pól edycyjnych, wyświetlany jest komunikat zgodny z obrazem 2, o treści: „<imie> <nazwisko> kolor oczu <kolor>", gdzie pola w nawiasach <> zostały pobrane z kontrolek.

    Kolor odczytujemy z przycisku opcji, który jest zaznaczony (IsChecked == true - typ bool?, jak w CheckBox), i składamy komunikat. Wpisz w podglądzie Jan, Nowak, wybierz „piwne” i kliknij „OK” - „Jan Nowak kolor oczu piwne” (obraz 2).

    desktopowa/MainWindow.xaml XAML zmienione: 2 linie
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="Wprowadzenie danych do paszportu. Wykonał: Bartosz Bryniarski" Height="330" Width="750"
            Background="#5F9EA0">
        <Grid Margin="20">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="330" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <StackPanel>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="110" />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Label Content="Numer" Margin="0,3" />
                    <TextBox x:Name="numberTextBox" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF"
                             LostFocus="NumberTextBox_LostFocus" />
                    <Label Grid.Row="1" Content="Imię" Margin="0,3" />
                    <TextBox x:Name="firstNameTextBox" Grid.Row="1" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF" />
                    <Label Grid.Row="2" Content="Nazwisko" Margin="0,3" />
                    <TextBox x:Name="lastNameTextBox" Grid.Row="2" Grid.Column="1" Margin="0,3" Height="20" Background="#F0FFFF" />
                </Grid>
                <GroupBox Header="Kolor oczu" Margin="0,20,0,0">
                    <StackPanel Margin="20,5">
                        <RadioButton x:Name="blueRadioButton" Content="niebieskie" IsChecked="True" Margin="0,5" />
                        <RadioButton x:Name="greenRadioButton" Content="zielone" Margin="0,5" />
                        <RadioButton x:Name="brownRadioButton" Content="piwne" Margin="0,5" />
                    </StackPanel>
                </GroupBox>
            </StackPanel>
            <StackPanel Grid.Column="1">
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                    <Image x:Name="photoImage" Height="180" Margin="10,0" />
                    <Image x:Name="fingerprintImage" Height="180" Margin="10,0" />
                </StackPanel>
                <Button Content="OK" Width="220" Height="35" Margin="0,20,0,0" Background="#F0FFFF"
                        Click="OkButton_Click" />
            </StackPanel>
        </Grid>
    </Window>
    desktopowa/MainWindow.xaml.cs C# zmienione: 18 linii
    using System.IO;
    using System.Windows;
    using System.Windows.Media.Imaging;
    
    namespace desktopowa;
    
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            LoadImages("000");
        }
    
        private void NumberTextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            LoadImages(numberTextBox.Text);
        }
    
        private void OkButton_Click(object sender, RoutedEventArgs e)
        {
            string color = "";
            if (blueRadioButton.IsChecked == true)
            {
                color = "niebieskie";
            }
            else if (greenRadioButton.IsChecked == true)
            {
                color = "zielone";
            }
            else if (brownRadioButton.IsChecked == true)
            {
                color = "piwne";
            }
            MessageBox.Show(firstNameTextBox.Text + " " + lastNameTextBox.Text + " kolor oczu " + color);
        }
    
        private void LoadImages(string number)
        {
            photoImage.Source = LoadImage(number + "-zdjecie.jpg");
            fingerprintImage.Source = LoadImage(number + "-odcisk.jpg");
        }
    
        private BitmapImage? LoadImage(string fileName)
        {
            string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
            if (!File.Exists(path))
            {
                return null;
            }
            return new BitmapImage(new Uri(path));
        }
    }
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  17. Krok 17: OK: komunikat Wprowadź dane przy pustych polach

    Kryteria:

    R.3.9 W przeciwnym do R.3.8 przypadku wyświetlane jest okienko komunikatu „Wprowadź dane” (sprawdzić w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    ok. 2 min
    Polecenie z arkusza

    Jeżeli nie wpisano imienia lub nazwiska, wyświetlany jest komunikat „Wprowadź dane”.

    Przed komunikatem sprawdzamy, czy któreś z pól jest puste (|| - „lub”). Sprawdzamy wszystkie trzy, bo poprzednie zdanie arkusza mówi o „wszystkich polach edycyjnych”. Kliknij „OK” w podglądzie bez imienia - pojawia się „Wprowadź dane” (R.3.9).

    desktopowa/MainWindow.xaml.cs C# zmienione: 8 linii
    using System.IO;
    using System.Windows;
    using System.Windows.Media.Imaging;
    
    namespace desktopowa;
    
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            LoadImages("000");
        }
    
        private void NumberTextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            LoadImages(numberTextBox.Text);
        }
    
        private void OkButton_Click(object sender, RoutedEventArgs e)
        {
            string color = "";
            if (blueRadioButton.IsChecked == true)
            {
                color = "niebieskie";
            }
            else if (greenRadioButton.IsChecked == true)
            {
                color = "zielone";
            }
            else if (brownRadioButton.IsChecked == true)
            {
                color = "piwne";
            }
            if (numberTextBox.Text == "" || firstNameTextBox.Text == "" || lastNameTextBox.Text == "")
            {
                MessageBox.Show("Wprowadź dane");
            }
            else
            {
                MessageBox.Show(firstNameTextBox.Text + " " + lastNameTextBox.Text + " kolor oczu " + color);
            }
        }
    
        private void LoadImages(string number)
        {
            photoImage.Source = LoadImage(number + "-zdjecie.jpg");
            fingerprintImage.Source = LoadImage(number + "-odcisk.jpg");
        }
    
        private BitmapImage? LoadImage(string fileName)
        {
            string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
            if (!File.Exists(path))
            {
                return null;
            }
            return new BitmapImage(new Uri(path));
        }
    }
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  18. Krok 18: Folder desktopowa: archiwum, źródła i plik wykonywalny

    ok. 2 min
    Polecenie z arkusza

    Kod aplikacji przygotuj do nagrania na płytę. W folderze desktopowa zapisz archiwum całego projektu o nazwie desktopowa.zip, pliki źródłowe, które były modyfikowane (interfejs użytkownika i logika aplikacji) oraz plik uruchomieniowy, jeżeli istnieje.

    Pakujemy folder projektu do desktopowa.zip (ze zdjęciami), obok kopiujemy MainWindow.xaml, MainWindow.xaml.cs i desktopowa.exe. Plik .exe uruchomiony z innego folderu potrzebuje zdjęć obok siebie - w bin\Debug\... są tam dzięki kopiowaniu do katalogu wyjściowego.

    Okno aplikacji bez zmian - taki jak po kroku 17.

  19. Etap 4: Dokumentacja aplikacji

    Kroki 19-22 · po tym etapie masz 33 z 33 kryteriów (pkt)

    Krok 19: Komentarz dokumentujący funkcję CheckControlSum

    Kryteria: , , , ,

    R.4.1 Dla dowolnej funkcji z aplikacji konsolowej zapisano nagłówek w postaci komentarza zgodny z Listingiem 1 z arkusza egzaminacyjnego (nie należy brać pod uwagę liczby gwiazdek), komentarz może być wieloliniowy lub kilka jednoliniowych, lub Docstrings (potrójny cudzysłów) - w ostatnim przypadku opis znajduje się pod słowem class (na początku definicji klasy)

    R.4.2 W komentarzu ujęto nazwę funkcji oraz opisano jej działanie

    R.4.3 W komentarzu ujęto wszystkie argumenty funkcji: nazwy i krótki opis

    R.4.4 W komentarzu ujęto nazwę typu zwracanego i krótki opis co jest zwracane

    R.4.5 W komentarzu ujęto numer zdającego

    ok. 4 min
    Polecenie z arkusza

    W kodzie źródłowym aplikacji konsolowej utwórz nagłówek dowolnej funkcji, według wzoru z listingu 1. W miejscu autor należy podać numer zdającego.

    Komentarz wieloliniowy nad funkcją, z polami listingu: nazwa i opis działania (R.4.2), parametr pesel z opisem (R.4.3), zwracany typ bool z opisem (R.4.4) i autor (R.4.5). Na egzaminie w polu autor wpisujemy numer PESEL - tu stoi Bartosz Bryniarski.

    konsola/Program.cs C# zmienione: 10 linii
    class Program
    {
        static char CheckGender(string pesel)
        {
            int genderDigit = pesel[9] - '0';
            if (genderDigit % 2 == 0)
            {
                return 'K';
            }
            else
            {
                return 'M';
            }
        }
    
        /*
         *****************************************************
         nazwa funkcji:       CheckControlSum
         opis funkcji:        sprawdza sumę kontrolną numeru PESEL: mnoży 10 pierwszych cyfr przez wagi
                              1, 3, 7, 9, ..., liczy S, M = S % 10 i R, a potem porównuje R z 11. cyfrą
         parametry:           pesel - numer PESEL zapisany jako napis (11 cyfr)
         zwracany typ i opis: bool - true, gdy suma kontrolna jest zgodna, false w przeciwnym razie
         autor:               Bartosz Bryniarski
         *****************************************************
         */
        static bool CheckControlSum(string pesel)
        {
            int[] weights = { 1, 3, 7, 9, 1, 3, 7, 9, 1, 3 };
            int S = 0;
            for (int i = 0; i < 10; i++)
            {
                S += (pesel[i] - '0') * weights[i];
            }
            int M = S % 10;
            int R;
            if (M == 0)
            {
                R = 0;
            }
            else
            {
                R = 10 - M;
            }
            return R == pesel[10] - '0';
        }
    
        static void Main()
        {
            string pesel = "55030101193";
            Console.Write("Podaj numer PESEL: ");
            pesel = Console.ReadLine();
    
            if (CheckGender(pesel) == 'K')
            {
                Console.WriteLine("Płeć: Kobieta");
            }
            else
            {
                Console.WriteLine("Płeć: Mężczyzna");
            }
    
            if (CheckControlSum(pesel))
            {
                Console.WriteLine("Suma kontrolna jest zgodna");
            }
            else
            {
                Console.WriteLine("Suma kontrolna jest niezgodna");
            }
        }
    }
    Wynik programu po tym kroku
    > konsola.exe
    Podaj numer PESEL: 55030101193
    Płeć: Mężczyzna
    Suma kontrolna jest zgodna
  20. Krok 20: Zrzuty konsola1 - konsola3

    Kryteria: , ,

    R.1.6 Podjęto próbę skompilowania kodu lub uruchomienia w interpreterze, co udokumentowano zrzutem przedstawiającym uruchomiony program lub jego kompilację

    R.2.8 Program uruchamia w konsoli, co udokumentowano zrzutem ekranu

    R.4.6 Zapisano przynajmniej jeden zrzut ekranu z uruchomienia lub kompilacji aplikacji konsolowej, na zrzucie widoczne jest środowisko, w którym powstała aplikacja

    ok. 3 min
    Polecenie z arkusza

    Wykonaj zrzuty ekranu dokumentujące uruchomienie aplikacji. Zrzuty powinny obejmować cały obszar ekranu monitora z widocznym paskiem zadań. Aplikacja konsolowa – zrzuty nazwane: konsola1, konsola2, ...

    Trzy uruchomienia ze środowiskiem w tle: PESEL mężczyzny i kobiety z poprawną sumą oraz numer z błędną ostatnią cyfrą - konsola1.png - konsola3.png w folderze dokumentacja.

    Wynik programu po tym kroku
    > konsola.exe
    Podaj numer PESEL: 55030101193
    Płeć: Mężczyzna
    Suma kontrolna jest zgodna
    
    > konsola.exe
    Podaj numer PESEL: 92071314764
    Płeć: Kobieta
    Suma kontrolna jest zgodna
    
    > konsola.exe
    Podaj numer PESEL: 55030101194
    Płeć: Mężczyzna
    Suma kontrolna jest niezgodna
  21. Krok 21: Zrzuty desktop1 - desktop4

    Kryteria:

    R.4.7 Zapisano przynajmniej jeden zrzut ekranu z uruchomienia lub kompilacji aplikacji desktopowej, na zrzucie widoczne jest środowisko, w którym powstała aplikacja

    ok. 4 min
    Polecenie z arkusza

    Aplikacja desktopowa – zrzuty nazwane: desktop1, desktop2, ...

    Uruchamiamy aplikację z Visual Studio i robimy zrzuty całego ekranu: desktop1 - stan początkowy ze zdjęciami 000 (obraz 1), desktop2 - po wpisaniu 333 i opuszczeniu pola (obraz 3), desktop3 - komunikat z danymi (obraz 2), desktop4 - „Wprowadź dane” przy pustym polu. Podgląd obok to aplikacja z poprzedniego kroku.

    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  22. Krok 22: Dokument egzamin

    Kryteria:

    R.4.8 Dokumentacja zawiera: nazwę systemu operacyjnego, nazwy środowisk, nazwy języków programowania

    ok. 2 min
    Polecenie z arkusza

    W edytorze tekstu pakietu biurowego utwórz plik z dokumentacją i nazwij go egzamin. Dokument powinien zawierać: nazwę systemu operacyjnego, nazwy środowisk programistycznych, nazwy języków programowania.

    W Wordzie albo Writerze dokument egzamin w folderze dokumentacja z trzema informacjami o narzędziach - tymi, których naprawdę używaliśmy.

    egzamin.txt Tekst nowy plik
    System operacyjny: Windows 11
    Środowisko programistyczne: Visual Studio 2022 (aplikacja konsolowa i desktopowa)
    Języki programowania: C# (aplikacja konsolowa), C# i XAML - WPF (aplikacja desktopowa)

    Okno aplikacji bez zmian - taki jak po kroku 21.

  23. Etap 5: Dobre praktyki (poza kluczem)

    Kroki 23-24 · po tym etapie masz 33 z 33 kryteriów (pkt)

    Krok 23: Konsola: sprawdzenie, czy PESEL ma 11 cyfr

    ok. 3 min
    Polecenie z arkusza

    Wczytanie z klawiatury numeru PESEL.

    Wersja z egzaminu przy krótszym numerze kończy się wyjątkiem IndexOutOfRangeException (pesel[10] nie istnieje), a przy literach liczy bzdury ('A' - '0' to 17). Pętla while pyta do skutku, dopóki numer nie ma dokładnie 11 znaków, i to samych cyfr (pesel.All(char.IsDigit) - metoda LINQ sprawdzająca każdy znak). ?? "" zamienia brak danych (koniec wejścia) na pusty napis.

    Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    konsola/Program.cs C# zmienione: 6 linii
    class Program
    {
        static char CheckGender(string pesel)
        {
            int genderDigit = pesel[9] - '0';
            if (genderDigit % 2 == 0)
            {
                return 'K';
            }
            else
            {
                return 'M';
            }
        }
    
        /*
         *****************************************************
         nazwa funkcji:       CheckControlSum
         opis funkcji:        sprawdza sumę kontrolną numeru PESEL: mnoży 10 pierwszych cyfr przez wagi
                              1, 3, 7, 9, ..., liczy S, M = S % 10 i R, a potem porównuje R z 11. cyfrą
         parametry:           pesel - numer PESEL zapisany jako napis (11 cyfr)
         zwracany typ i opis: bool - true, gdy suma kontrolna jest zgodna, false w przeciwnym razie
         autor:               Bartosz Bryniarski
         *****************************************************
         */
        static bool CheckControlSum(string pesel)
        {
            int[] weights = { 1, 3, 7, 9, 1, 3, 7, 9, 1, 3 };
            int S = 0;
            for (int i = 0; i < 10; i++)
            {
                S += (pesel[i] - '0') * weights[i];
            }
            int M = S % 10;
            int R;
            if (M == 0)
            {
                R = 0;
            }
            else
            {
                R = 10 - M;
            }
            return R == pesel[10] - '0';
        }
    
        static void Main()
        {
            string pesel = "55030101193";
            Console.Write("Podaj numer PESEL: ");
            pesel = Console.ReadLine() ?? "";
            while (pesel.Length != 11 || !pesel.All(char.IsDigit))
            {
                Console.Write("PESEL ma 11 cyfr. Podaj numer PESEL: ");
                pesel = Console.ReadLine() ?? "";
            }
    
            if (CheckGender(pesel) == 'K')
            {
                Console.WriteLine("Płeć: Kobieta");
            }
            else
            {
                Console.WriteLine("Płeć: Mężczyzna");
            }
    
            if (CheckControlSum(pesel))
            {
                Console.WriteLine("Suma kontrolna jest zgodna");
            }
            else
            {
                Console.WriteLine("Suma kontrolna jest niezgodna");
            }
        }
    }
    Wynik programu po tym kroku
    > konsola.exe
    Podaj numer PESEL: 55030101193
    Płeć: Mężczyzna
    Suma kontrolna jest zgodna
  24. Krok 24: Okno: pola ze spacjami też są puste

    ok. 3 min
    Polecenie z arkusza

    Jeżeli nie wpisano imienia lub nazwiska, wyświetlany jest komunikat „Wprowadź dane”.

    Porównanie z "" przepuszcza pole z samą spacją - komunikat wyglądałby wtedy jak „ kolor oczu niebieskie”. string.IsNullOrWhiteSpace traktuje jako puste także pola z samymi odstępami, a Trim() obcina przypadkowe spacje na początku i końcu imienia. Komunikat składamy napisem interpolowanym $"..." - czytelniej niż sklejanie plusami.

    Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    desktopowa/MainWindow.xaml.cs C# zmienione: 3 linie
    using System.IO;
    using System.Windows;
    using System.Windows.Media.Imaging;
    
    namespace desktopowa;
    
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            LoadImages("000");
        }
    
        private void NumberTextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            LoadImages(numberTextBox.Text);
        }
    
        private void OkButton_Click(object sender, RoutedEventArgs e)
        {
            string color = "";
            if (blueRadioButton.IsChecked == true)
            {
                color = "niebieskie";
            }
            else if (greenRadioButton.IsChecked == true)
            {
                color = "zielone";
            }
            else if (brownRadioButton.IsChecked == true)
            {
                color = "piwne";
            }
            if (string.IsNullOrWhiteSpace(numberTextBox.Text) || string.IsNullOrWhiteSpace(firstNameTextBox.Text)
                || string.IsNullOrWhiteSpace(lastNameTextBox.Text))
            {
                MessageBox.Show("Wprowadź dane");
            }
            else
            {
                MessageBox.Show($"{firstNameTextBox.Text.Trim()} {lastNameTextBox.Text.Trim()} kolor oczu {color}");
            }
        }
    
        private void LoadImages(string number)
        {
            photoImage.Source = LoadImage(number + "-zdjecie.jpg");
            fingerprintImage.Source = LoadImage(number + "-odcisk.jpg");
        }
    
        private BitmapImage? LoadImage(string fileName)
        {
            string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
            if (!File.Exists(path))
            {
                return null;
            }
            return new BitmapImage(new Uri(path));
        }
    }
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  25. Etap 6: Oddanie pracy

    Krok 25 · po tym etapie masz 33 z 33 kryteriów (pkt)

    Krok 25: Nagranie płyty

    ok. 5 min
    Polecenie z arkusza

    Nagraj płytę z rezultatami pracy. W folderze z numerem zdającego powinny się znajdować podfoldery konsola, desktopowa, dokumentacja.

    Sprawdzamy zawartość przed nagraniem:

    • dokumentacja: konsola1.png - konsola3.png, desktop1.png - desktop4.png, egzamin,
    • konsola: konsola.zip (spakowany po dopisaniu komentarza), Program.cs, konsola.exe,
    • desktopowa: desktopowa.zip, MainWindow.xaml, MainWindow.xaml.cs, desktopowa.exe.

    Nagrywamy, sprawdzamy odczyt płyty, opisujemy ją numerem zdającego.

    Okno aplikacji bez zmian - taki jak po kroku 24.

Podgląd

To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.

Autor rozwiązania: . Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony). Treść arkusza i klucza oceniania pochodzi z CKE.