Dane modelu:
Każdy produkt powinien być reprezentowany przez obiekt klasycznie zgodny z Produkt funkcjami:
Id – numer identyfikacyjny generowany automatycznie.
Nazwa – nazwa produktu.
Ilosc – ilość sztuk.
CenaJednostkowa – cena jednej sztuki.
Łączna wartość produktu obliczona jest jako iloczyn Ilosc * CenaJednostkowa.
Główny ekran aplikacji (Strona Główna):
Powinien zawierać pole odprowadzające (Entry) do dalszych danych nowego produktu:
Nazwa produktu,
Ilość (tylko liczby),
Cena jednostkowa (tylko, format dziesiętny).
Powinien zawierać przycisk Dodaj , który dodaje nowy produkt do składu po rozwiniętej walidacji danych.
Powinien wyświetlać listę produktów w kontroli CollectionView z wyborem elementu.
Może zawierać Edytuj i usunąć :
Po zaznaczeniu produktu Edytuj użytkownika, który przechodzi do wydanego ekranu.
Po usunięciu produktu, który pozostał z list.
Na ekranie znajduje się etykieta, która wyświetla łączną wartość magazynu (suma wartości wszystkich produktów).
Edycja ekranu produktu (EditProductPage):
Może umożliwić modyfikację danych produktu.
Pola tekstowe (Entry) być dostępne w postaci aktualnej wersji produktu.
Po zatwierdzeniu zmian (przycisk zapisu ) produkt pozostaje zaktualizowany w głównej liście, a zmiana odzwierciedlona na następującym ekranie.
ograniczona możliwość anulowania edycji (przycisk Anuluj ).
Trwałe przechowywanie danych:
Aplikacja musi umożliwiać zapisywanie list produktów do pliku CSV oraz wczytanie danych z tego pliku.
Ścieżka do pliku może być oparta na FileSystem.AppDataDirectory (zapewnia dostęp do źródła dla danych aplikacji).
Środowisko: Visual Studio 2022, .NET MAUI (C#).
Struktura projektu:
Projekt powinien zawierać co najmniej dwie strony:
MainPage.xaml – główny ekran aplikacji.
EditProductPage.xaml – edycja ekranu edycji produktu.
Obsługa nawigacji:
Aplikacja umożliwia przechodzenie między stronami przy użyciu korzystania z nawigacji w .NET MAUI.
Wiązanie danych:
Lista produktów przechowywanych w kolekcji typu ObservableCollection <Produkt>, co umożliwia automatyczne odświeżanie widoku (CollectionView).
Walidacja danych:
Wszelkie dane wejściowe (np. nazwa, ilość, cena) muszą być walidowane przed ich przetworzeniem. W przypadku niepoprawnych danych użytkownika powinien otrzymać komunikat o zastosowaniu.
Utworzenie projektu:
W Visual Studio 2022 utwórz nowego projektu typu .NET MAUI App i nadaj mu potrzebę, np. MauiProductApp.
Projektowanie interfejsu internetowego (MainPage.xaml): 🕷️
Miejsce na stronie:
Wpis do nazwy produktu ( entryNazwa),
Wejście do ilości ( entryIlosc) – z wyprowadzoną numeryczną,
Wpis do ceny jednostkowej ( entryCena) – z ustawioną komórką numeryczną.
Przycisk z napisem Dodaj i odłączam kliknięcie OnDodajClicked.
CollectionView ( collectionViewProdukty) do listy produktów z trybem zaznaczenia elementu.
Buttony : Edytuj ( OnEdytujClicked) oraz Usuń ( OnUsunClicked).
Etykieta wyświetlająca łączną wartość pamięci ( labelWartoscMagazynu).
Przyciski do zapisu i wczytywania danych ( Zapisz – OnZapiszClicked, Wczytaj – OnWczytajClicked).
Implementacja logiki ekranu ekranu (MainPage.xaml.cs):
Zdefiniuj klasę Produkt z właściwościami: Id, Nazwa, Ilosc, CenaJednostkowa.
Utwórz bazę ObservableCollection <Produkt> listaProduktow i przypisz ją jako źródło danych dla CollectionView.
Zaimplementuj instalację OnDodajClicked, która:
Odczytuje dane z pól Entry,
Waliduje dane wejściowe,
Tworzy nowy obiekt Produkt z automatycznie generowanym identyfikatorem,
Dodaj produkty do list odświeżania widoku oraz etykiet z łączną wartością magazynową.
Zaimplementuj instalację OnEdytujClicked, która:
Sprawdza, czy użytkownik produktu,
W przypadku przejścia do ekranu edycji ( EditProductPage), przekazując wybór produktu.
Zaimplementuj urządzenie OnUsunClicked, które jest oznaczone produktem z listami i odświeżaniem widoku.
Zaimplementuj metody OnZapiszClickedi OnWczytajClicked, które zapisują i wczytują dane do/z pliku CSV, kluczem kontrolnym opartą na FileSystem.AppDataDirectory.
Zaimplementuj AktualizujWartoscMagazynu, który iteruje przez listę produktów i wylicza sumę wartości (Ilosc * CenaJednostkowa), a wynik wyświetla w etykiecie.
Utworzenie ekranu edycji produktu (EditProductPage):
Utwórz nową stronę typu .NET MAUI Content Page (XAML) o nazwie EditProductPage.xaml.
Na tej stronie kontrolerów kontrolnych:
Wpis dla nazwy produktu,
Wpis dla ilości,
Wpis dla ceny jednostkowej,
Przycisk z napisem Zapisz i kliknij kliknięcia OnZapiszClicked,
Przycisk z napisem Anuluj i kliknięcia OnAnulujClicked.
W kodzie (EditProductPage.xaml.cs):
W konstruktorze pobierz udostępniany obiekt produktu i przypisz jego dane do pól Entry.
W metodzie OnZapiszClicked kontroli walidacji danych, z aktualizacji właściwości produktu oraz powróć do ekranu ekranu (przy użyciu nawigacji).
W metodzie OnAnulujClicked po prostu powróć do ekranu bez zmian.
Testowanie aplikacji:
Aplikacja aplikacyjna w emulatorze lub na urządzeniu mobilnym.
Sprawdź, czy możesz:
Dodawaj nowe produkty,
Edytować wybór produktu (poprzez otwarcie ekranu edycji),
Usuwać produkty,
Zapis i wczytywanie danych nieprawidłowych,
Łączna wartość magazynu jest zabezpieczona obliczana i wyświetlana.
Metoda aktualizacjiWartoscMagazynu() ma za zadanie:
Przejrzeć całą zawartość produktów, która jest przechowywana w obiekcie typu ObservableCollection<Produkt>.
Dla każdego produktu wytwarzającego jego wartość jako iloczyn ilości (Ilosc) i ceny jednostkowej (CenaJednostkowa) .
Zsumować wartości wszystkich produktów.
Wyświetlanie wyników w odpowiednim etykiecie na ekranie (np. labelWartoscMagazynu).
Wykorzystaliśmy do tego celu składnię LINQ, która umożliwia zdalne i czytelne operacje na odbiór. Dokładnie:
Metoda Sum jest wywoływana w kolekcji produktów.
Dla każdego elementu kolekcji (każdego przedmiotu Produkt) oznaczenie lambda p => p.Ilosc * p.CenaJednostkowa oblicza wartość określonego produktu.
Wynikiem wywołania listaProduktow.Sum(...)jest suma wartości wszystkich produktów w kolekcji.
Przykładowa implementacja wygląda na twierdzenia:
private void AktualizujWartoscMagazynu()
{
// Obliczenie sumy – dla każdego produktu p mnożymy ilość przez cenę jednostkową
decimal suma = listaProduktow.Sum(p => p.Ilosc * p.CenaJednostkowa);
// Aktualizacja etykiety, aby wyświetlić wynik na ekranie
labelWartoscMagazynu.Text = $"Łączna wartość magazynu: {suma} zł";
}
listaProduktów:
To obiekt typu ObservableCollection<Produkt>, w którym znajdują się wszystkie produkty. Dzięki wykorzystaniu tej kolekcji widoku (CollectionView) automatycznie odświeża się przy dodawaniu lub usuwaniu produktów.
Metoda sumy:
listaProduktow.Sum(p => p.Ilosc * p.CenaJednostkowa) przegląd każdego elementu kolekcji. Dla danego produktu p mnoży wartość pola Ilosc przez wartość pola CenaJednostkowa. Wynikiem tego jest wartość danego produktu, funkcja Sum dodająca te wartości dla wszystkich produktów, tworząca łączną wartość pamięci.
aktualizacja aktualizacji:
Po obliczeniu sumy przypisujemy wynik do oceny Text wagi labelWartoscMagazynu, aby użytkownik mógł zobaczyć wartość produktu w wersji tekstowej.
Czytelność:
Zamiast pisać pętlę foreach do iteracji po kolekcji i ręcznego sumowania, używając metod LINQ Sum zapisuje cały proces w jednej linii. Dzięki temu kod jest bardziej zwięzły i łatwo dostępny.
Efektywność:
LINQ jest uprawniona do operacji na odbiór i pozwala na szybkie przesłanie danych.
Funkcja ma na celu zapisanie bieżącej listy produktów do pliku CSV, aby dane mogły być później przywrócone. Format CSV umożliwia udostępnianie danych w postaci tekstowej, gdzie poszczególne wartości są oddzielone separatorem (np. średnim).
Ustalenie ścieżki zapisu:
Używamy Path.Combine(FileSystem.AppDataDirectory, "produkty.csv"), aby wygenerować dostępne do pliku o nazwie „produkty.csv” umieszczonego w katalogu przeznaczonym do danych aplikacji. Dzięki temu aplikacja ma dostęp do tego rozszerzenia platformy.
Otwieranie pliku do zapisu:
Wykorzystujemy using (var writer = new StreamWriter(filePath)), co zapewnia, że po usunięciu pliku następuje zamknięcie (nawet w przypadku wystąpienia wtórnego).
Zapiski z książki:
Na początek zapisu zapisu jest linia nagłówkowa (np. "Id;Nazwa;Ilosc;CenaJednostkowa"). Dzięki temu w przyszłości przy wczytywaniu danych można uzyskać pierwszy wiersz.
Produkty zapisu danych:
Dla każdego produktu z kolekcji listaProduktow zapisujemy do pliku pojedynczego tekstu. W tej linii poszczególnych właściwości produktu (takie jak Id , Nazwa , Ilosc oraz CenaJednostkowa ) są oddzielonymi średnimi. Dzięki temu plik CSV ma strukturę tekstową, w każdym wierszu jednego produktu, a pola są oddzielone wybranym separatorem (w naszym przypadku średnim).
Przykładowa linia zapisu:
Jeśli mamy produkt o dostępie do danych:
Identyfikator : 1
Nazwa : Mleko
Ilość : 10
CenaJednostkowa : 2.50
do linii zapisu w pliku CSV będą rozważane wnioski:
1;Mleko;10;2.50
Lista:
szyfrowanie zapisu, które znajduje się w bloku try-catch, pozwala na wyłapanie błędów (np. brak uprawnień do zapisu, problem z dyskiem). W przypadku zastosowania wyjątku konsumenta otrzymującego komunikat właściwy.
private async void OnZapiszClicked(object sender, EventArgs e)
{
try
{
// Ustalenie ścieżki do pliku w lokalnym katalogu aplikacji
string filePath = Path.Combine(FileSystem.AppDataDirectory, "produkty.csv");
using (var writer = new StreamWriter(filePath))
{
// Zapis nagłówka pliku CSV
writer.WriteLine("Id;Nazwa;Ilosc;CenaJednostkowa");
// Zapis danych dla każdego produktu
foreach (var produkt in listaProduktow)
{
writer.WriteLine($"{produkt.Id};{produkt.Nazwa};{produkt.Ilosc};{produkt.CenaJednostkowa}");
}
}
await DisplayAlert("Informacja", "Dane zapisane pomyślnie.", "OK");
}
catch (Exception ex)
{
await DisplayAlert("Błąd", $"Błąd zapisu: {ex.Message}", "OK");
}
}
Funkcja ma za zadanie wczytanie danych z pliku CSV (zapisanego wcześniej przez potwierdzenie zapisu) do listy produktów w aplikacji. Dzięki temu użytkownik może zastosować stan oprogramowania po uruchomieniu aplikacji.
Ustalona ścieżka do pliku:
jak funkcja w zapisie, która następnie następuje Path.Combine(FileSystem.AppDataDirectory, "produkty.csv"), aby uzyskać dostęp do pliku.
Obecność substancji:
Przed próbą odczytu sprawdzamy, czy plik faktycznie istnieje przy użyciu File.Exists(filePath). Jeśli plik nie istnieje, używamy użytkownika i kończy się działanie funkcji.
Odczytaj zawartość pliku:
Korzystamy z metod File.ReadAllLines(filePath), które odczytują wszystkie linie z pliku i zwracają tablicę łańcuchów znaków. Pierwsza linia do nagłówka, więc jest pomijana podczas przetwarzania.
Parsowanie danych i tworzenie obiektów:
Iterujemy po każdej linii (pomijając nagłówek) i rozdzielamy dane na poszczególne elementy przy stosowaniu metod Split(';').
Dla każdej linii, liczba elementów jest zgodna z oczekiwaniami (4 pola), tworzymy nowy obiekt klasy Produkti przypisujemy odczytane wartości (konwertując je na typ: intdla ilości, decimaldla cen).
Aktualizacja kolekcji:
Dodajemy każdy obiekt do kolekcji listaProduktow, który jest powiązany z widokiem (CollectionView) za pomocą ObservableCollection.
Na końcu aktualizujemy zmienną identyfikującą kolejny identyfikator, aby nowo dodane produkty różnił się Id.
Lista:
Cały proces odczytu i parsowania znajduje się w bloku try-catch, co pozwala na wykrycie błędów (np. błędny format danych w pliku). W przypadku wykorzystania użytkownika użytkowego komunikatu.
private async void OnWczytajClicked(object sender, EventArgs e)
{
try
{
// Ustalenie ścieżki do pliku w lokalnym katalogu aplikacji
string filePath = Path.Combine(FileSystem.AppDataDirectory, "produkty.csv");
if (!File.Exists(filePath))
{
await DisplayAlert("Informacja", "Plik nie istnieje.", "OK");
return;
}
// Czyszczenie bieżącej listy produktów
listaProduktow.Clear();
// Odczyt wszystkich linii z pliku
var lines = File.ReadAllLines(filePath);
// Pomijamy pierwszy wiersz (nagłówek)
for (int i = 1; i < lines.Length; i++)
{
var parts = lines[i].Split(';');
if (parts.Length == 4)
{
var produkt = new Produkt
{
Id = int.Parse(parts[0]),
Nazwa = parts[1],
Ilosc = int.Parse(parts[2]),
CenaJednostkowa = decimal.Parse(parts[3])
};
listaProduktow.Add(produkt);
}
}
// Ustalenie kolejnego Id na podstawie maksymalnego Id wczytanych produktów
kolejnyId = listaProduktow.Any() ? listaProduktow.Max(p => p.Id) + 1 : 1;
AktualizujWartoscMagazynu();
await DisplayAlert("Informacja", "Dane wczytane pomyślnie.", "OK");
}
catch (Exception ex)
{
await DisplayAlert("Błąd", $"Błąd wczytywania danych: {ex.Message}", "OK");
}
}
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="MauiProductApp.MainPage"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Title="Magazyn Produktów">
<StackLayout Padding="10" Spacing="10">
<!-- Sekcja dodawania produktu -->
<Label Text="Dodaj nowy produkt:" FontAttributes="Bold"/>
<Entry x:Name="entryNazwa" Placeholder="Nazwa produktu" />
<Entry x:Name="entryIlosc" Placeholder="Ilość" Keyboard="Numeric" />
<Entry x:Name="entryCena" Placeholder="Cena jednostkowa" Keyboard="Numeric" />
<Button Text="Dodaj" Clicked="OnDodajClicked"/>
<!-- Przyciski operacyjne -->
<StackLayout Orientation="Horizontal" Spacing="10">
<Button Text="Edytuj" Clicked="OnEdytujClicked"/>
<Button Text="Usuń" Clicked="OnUsunClicked"/>
</StackLayout>
<!-- Lista produktów -->
<CollectionView x:Name="collectionViewProdukty" SelectionMode="Single" SelectionChanged="OnSelectionChanged">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- Wyświetla nazwę produktu -->
<Label Text="{Binding Nazwa}" FontAttributes="Bold" Grid.Column="0"/>
<!-- Wyświetla ilość (możesz dodać więcej danych) -->
<Label Text="{Binding Ilosc}" Grid.Column="1" HorizontalOptions="End"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<!-- Łączna wartość magazynu -->
<Label x:Name="labelWartoscMagazynu" Text="Łączna wartość magazynu: 0 zł" FontAttributes="Bold"/>
<!-- Przyciski zapisu/wczytania danych -->
<StackLayout Orientation="Horizontal" Spacing="10">
<Button Text="Zapisz" Clicked="OnZapiszClicked"/>
<Button Text="Wczytaj" Clicked="OnWczytajClicked"/>
</StackLayout>
</StackLayout>
</ContentPage>
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using Microsoft.Maui.Controls;
namespace MauiProductApp
{
public partial class MainPage : ContentPage
{
// Lista produktów – używamy ObservableCollection, aby automatycznie odświeżać widok
private ObservableCollection<Produkt> listaProduktow = new ObservableCollection<Produkt>();
private int kolejnyId = 1;
public MainPage()
{
InitializeComponent();
collectionViewProdukty.ItemsSource = listaProduktow;
}
// Dodawanie nowego produktu
private void OnDodajClicked(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(entryNazwa.Text) ||
!int.TryParse(entryIlosc.Text, out int ilosc) ||
!decimal.TryParse(entryCena.Text, out decimal cena))
{
DisplayAlert("Błąd", "Wprowadź poprawne dane produktu.", "OK");
return;
}
var produkt = new Produkt
{
Id = kolejnyId++,
Nazwa = entryNazwa.Text,
Ilosc = ilosc,
CenaJednostkowa = cena
};
listaProduktow.Add(produkt);
AktualizujWartoscMagazynu();
ClearFields();
}
// Edycja wybranego produktu – po zaznaczeniu otwiera się ekran edycji
private async void OnEdytujClicked(object sender, EventArgs e)
{
if (collectionViewProdukty.SelectedItem is Produkt selectedProdukt)
{
// Przechodzimy do ekranu edycji, przekazując wybrany produkt
var editPage = new EditProductPage(selectedProdukt);
await Navigation.PushAsync(editPage);
// Po powrocie odświeżamy widok i łączną wartość
AktualizujWartoscMagazynu();
collectionViewProdukty.SelectedItem = null;
}
else
{
await DisplayAlert("Informacja", "Proszę wybrać produkt do edycji.", "OK");
}
}
// Usuwanie wybranego produktu
private void OnUsunClicked(object sender, EventArgs e)
{
if (collectionViewProdukty.SelectedItem is Produkt selectedProdukt)
{
listaProduktow.Remove(selectedProdukt);
AktualizujWartoscMagazynu();
collectionViewProdukty.SelectedItem = null;
}
else
{
DisplayAlert("Informacja", "Proszę wybrać produkt do usunięcia.", "OK");
}
}
// Oblicza łączną wartość magazynu i aktualizuje etykietę
private void AktualizujWartoscMagazynu()
{
decimal suma = listaProduktow.Sum(p => p.Ilosc * p.CenaJednostkowa);
labelWartoscMagazynu.Text = $"Łączna wartość magazynu: {suma} zł";
}
// Czyści pola wejściowe
private void ClearFields()
{
entryNazwa.Text = string.Empty;
entryIlosc.Text = string.Empty;
entryCena.Text = string.Empty;
}
// Zapis danych do pliku CSV
private async void OnZapiszClicked(object sender, EventArgs e)
{
try
{
string filePath = Path.Combine(FileSystem.AppDataDirectory, "produkty.csv");
using (var writer = new StreamWriter(filePath))
{
writer.WriteLine("Id;Nazwa;Ilosc;CenaJednostkowa");
foreach (var produkt in listaProduktow)
{
writer.WriteLine($"{produkt.Id};{produkt.Nazwa};{produkt.Ilosc};{produkt.CenaJednostkowa}");
}
}
await DisplayAlert("Informacja", "Dane zapisane pomyślnie.", "OK");
}
catch (Exception ex)
{
await DisplayAlert("Błąd", $"Błąd zapisu: {ex.Message}", "OK");
}
}
// Wczytywanie danych z pliku CSV
private async void OnWczytajClicked(object sender, EventArgs e)
{
try
{
string filePath = Path.Combine(FileSystem.AppDataDirectory, "produkty.csv");
if (!File.Exists(filePath))
{
await DisplayAlert("Informacja", "Plik nie istnieje.", "OK");
return;
}
listaProduktow.Clear();
var lines = File.ReadAllLines(filePath);
for (int i = 1; i < lines.Length; i++)
{
var parts = lines[i].Split(';');
if (parts.Length == 4)
{
var produkt = new Produkt
{
Id = int.Parse(parts[0]),
Nazwa = parts[1],
Ilosc = int.Parse(parts[2]),
CenaJednostkowa = decimal.Parse(parts[3])
};
listaProduktow.Add(produkt);
}
}
// Aktualizacja kolejnego identyfikatora
if (listaProduktow.Any())
kolejnyId = listaProduktow.Max(p => p.Id) + 1;
else
kolejnyId = 1;
AktualizujWartoscMagazynu();
await DisplayAlert("Informacja", "Dane wczytane pomyślnie.", "OK");
}
catch (Exception ex)
{
await DisplayAlert("Błąd", $"Błąd wczytywania danych: {ex.Message}", "OK");
}
}
// (Opcjonalnie) Obsługa zmiany zaznaczenia – możesz dodać logikę, jeśli potrzebujesz
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Możesz obsłużyć np. automatyczne zaznaczenie wiersza
}
}
// Model produktu – definiuje właściwości produktu
public class Produkt
{
public int Id { get; set; }
public string Nazwa { get; set; }
public int Ilosc { get; set; }
public decimal CenaJednostkowa { get; set; }
}
}
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="MauiProductApp.EditProductPage"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Title="Edycja produktu">
<StackLayout Padding="10" Spacing="10">
<Label Text="Edytuj produkt:" FontAttributes="Bold"/>
<Entry x:Name="entryNazwa" Placeholder="Nazwa produktu"/>
<Entry x:Name="entryIlosc" Placeholder="Ilość" Keyboard="Numeric"/>
<Entry x:Name="entryCena" Placeholder="Cena jednostkowa" Keyboard="Numeric"/>
<Button Text="Zapisz" Clicked="OnZapiszClicked"/>
<Button Text="Anuluj" Clicked="OnAnulujClicked"/>
</StackLayout>
</ContentPage>
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using Microsoft.Maui.Controls;
namespace MauiProductApp
{
public partial class MainPage : ContentPage
{
// Lista produktów – używamy ObservableCollection, aby automatycznie odświeżać widok
private ObservableCollection<Produkt> listaProduktow = new ObservableCollection<Produkt>();
private int kolejnyId = 1;
public MainPage()
{
InitializeComponent();
collectionViewProdukty.ItemsSource = listaProduktow;
}
// Dodawanie nowego produktu
private void OnDodajClicked(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(entryNazwa.Text) ||
!int.TryParse(entryIlosc.Text, out int ilosc) ||
!decimal.TryParse(entryCena.Text, out decimal cena))
{
DisplayAlert("Błąd", "Wprowadź poprawne dane produktu.", "OK");
return;
}
var produkt = new Produkt
{
Id = kolejnyId++,
Nazwa = entryNazwa.Text,
Ilosc = ilosc,
CenaJednostkowa = cena
};
listaProduktow.Add(produkt);
AktualizujWartoscMagazynu();
ClearFields();
}
// Edycja wybranego produktu – po zaznaczeniu otwiera się ekran edycji
private async void OnEdytujClicked(object sender, EventArgs e)
{
if (collectionViewProdukty.SelectedItem is Produkt selectedProdukt)
{
// Przechodzimy do ekranu edycji, przekazując wybrany produkt
var editPage = new EditProductPage(selectedProdukt);
await Navigation.PushAsync(editPage);
// Po powrocie odświeżamy widok i łączną wartość
AktualizujWartoscMagazynu();
collectionViewProdukty.SelectedItem = null;
}
else
{
await DisplayAlert("Informacja", "Proszę wybrać produkt do edycji.", "OK");
}
}
// Usuwanie wybranego produktu
private void OnUsunClicked(object sender, EventArgs e)
{
if (collectionViewProdukty.SelectedItem is Produkt selectedProdukt)
{
listaProduktow.Remove(selectedProdukt);
AktualizujWartoscMagazynu();
collectionViewProdukty.SelectedItem = null;
}
else
{
DisplayAlert("Informacja", "Proszę wybrać produkt do usunięcia.", "OK");
}
}
// Oblicza łączną wartość magazynu i aktualizuje etykietę
private void AktualizujWartoscMagazynu()
{
decimal suma = listaProduktow.Sum(p => p.Ilosc * p.CenaJednostkowa);
labelWartoscMagazynu.Text = $"Łączna wartość magazynu: {suma} zł";
}
// Czyści pola wejściowe
private void ClearFields()
{
entryNazwa.Text = string.Empty;
entryIlosc.Text = string.Empty;
entryCena.Text = string.Empty;
}
// Zapis danych do pliku CSV
private async void OnZapiszClicked(object sender, EventArgs e)
{
try
{
string filePath = Path.Combine(FileSystem.AppDataDirectory, "produkty.csv");
using (var writer = new StreamWriter(filePath))
{
writer.WriteLine("Id;Nazwa;Ilosc;CenaJednostkowa");
foreach (var produkt in listaProduktow)
{
writer.WriteLine($"{produkt.Id};{produkt.Nazwa};{produkt.Ilosc};{produkt.CenaJednostkowa}");
}
}
await DisplayAlert("Informacja", "Dane zapisane pomyślnie.", "OK");
}
catch (Exception ex)
{
await DisplayAlert("Błąd", $"Błąd zapisu: {ex.Message}", "OK");
}
}
// Wczytywanie danych z pliku CSV
private async void OnWczytajClicked(object sender, EventArgs e)
{
try
{
string filePath = Path.Combine(FileSystem.AppDataDirectory, "produkty.csv");
if (!File.Exists(filePath))
{
await DisplayAlert("Informacja", "Plik nie istnieje.", "OK");
return;
}
listaProduktow.Clear();
var lines = File.ReadAllLines(filePath);
for (int i = 1; i < lines.Length; i++)
{
var parts = lines[i].Split(';');
if (parts.Length == 4)
{
var produkt = new Produkt
{
Id = int.Parse(parts[0]),
Nazwa = parts[1],
Ilosc = int.Parse(parts[2]),
CenaJednostkowa = decimal.Parse(parts[3])
};
listaProduktow.Add(produkt);
}
}
// Aktualizacja kolejnego identyfikatora
if (listaProduktow.Any())
kolejnyId = listaProduktow.Max(p => p.Id) + 1;
else
kolejnyId = 1;
AktualizujWartoscMagazynu();
await DisplayAlert("Informacja", "Dane wczytane pomyślnie.", "OK");
}
catch (Exception ex)
{
await DisplayAlert("Błąd", $"Błąd wczytywania danych: {ex.Message}", "OK");
}
}
// (Opcjonalnie) Obsługa zmiany zaznaczenia – możesz dodać logikę, jeśli potrzebujesz
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Możesz obsłużyć np. automatyczne zaznaczenie wiersza
}
}
// Model produktu – definiuje właściwości produktu
public class Produkt
{
public int Id { get; set; }
public string Nazwa { get; set; }
public int Ilosc { get; set; }
public decimal CenaJednostkowa { get; set; }
}
}
Zadanie - EGZ-arkusz-praktyczny-inf04-2021-06-01
Oznaczenie: INF.04-01-21.06-SG Limit czasu: 150 minut
Wykonaj aplikację konsolową oraz mobilną według wskazań. Udokumentuj obie aplikacje zrzutami ekranu i komentarzami zgodnie z opisem w części III instrukcji do zadania. W tym celu zaloguj się na konto Egzamin bez hasła.
Utwórz folder i nazwij go swoim numerem PESEL. W folderze utwórz trzy podfoldery: konsola, mobilna, dokumentacja. Po wykonaniu każdej aplikacji, jej pełny kod (cały projekt) skopiuj do odpowiedniego folderu. Dokumentację obu aplikacji w postaci zrzutów ekranu i dokumentu umieść w podfolderze dokumentacja.
Część I. Aplikacja konsolowa
Napisz program sortujący tablicę metodą przez wybieranie według zamieszczonej dokumentacji:
Sortowanie przez wybieranie - jedna z prostszych metod sortowania o złożoności O(n2). Polega na wyszukaniu elementu mającego się znaleźć na żądanej pozycji i zamianie miejscami z tym, który jest tam obecnie. Operacja jest wykonywana dla wszystkich indeksów sortowanej tablicy.
Algorytm przedstawia się następująco:
wyszukaj minimalną wartość z tablicy spośród elementów od i do końca tablicy
zamień wartość minimalną, z elementem na pozycji i
Gdy zamiast wartości minimalnej wybierana będzie maksymalna, wówczas tablica będzie posortowana od największego do najmniejszego elementu.
Założenia do programu
Program wykonywany w konsoli
Obiektowy język programowania zgodny z zainstalowanym na stanowisku egzaminacyjnym: C++ lub C# lub Java lub Python
Sortowanie odbywa się malejąco, nie wykorzystuje gotowych funkcji do sortowania oraz do szukania maksimum
Sortowana jest tablica 10 liczb całkowitych. Tablica jest polem klasy
Tablica jest wczytywana z klawiatury po uprzednim wypisaniu odpowiedniego komunikatu
Wszystkie elementy posortowanej tablicy są wyświetlane na ekranie
Klasa zawiera co najmniej dwie metody: sortującą i szukającą wartość najwyższą. Widzialność metody szukającej ogranicza się jedynie do klasy
Metoda szukająca zwraca wartość, w zależności od przyjętej taktyki może być to wartość maksymalna lub index wartości maksymalnej
Program powinien być zapisany czytelnie, z zasadami czystego formatowania kodu, należy stosować znaczące nazwy zmiennych i funkcji
Dokumentacja do programu wykonana zgodnie z wytycznymi z części III zadania egzaminacyjnego
Kod aplikacji (cały folder projektu) przygotuj do nagrania na płytę (skopiuj do folderu z numerem PESEL, do podfolderu konsola).
Część II. Aplikacja mobilna
Wykonaj aplikację mobilną za pomocą środowiska programistycznego dostępnego na stanowisku egzaminacyjnym oraz uruchom ją w dostępnym emulatorze systemu mobilnego.
Obraz 1a. Emulacja na urządzeniu Nexus 5X API 29 x86. Aplikację utworzono w Android Studio
Obraz 1b. Emulacja na systemie Android Oreo. Aplikację utworzono w MS Visual Studio
Na obrazach 1a i 1b przedstawiono działanie aplikacji mobilnej. W zależności od użytego środowiska programistycznego oraz emulowanego systemu wynik końcowy może nieznacznie się różnić.
Opis wyglądu aplikacji
Napis „Rejestruj konto”
Napis „Podaj e-mail:”, a pod nim pole edycyjne z podpowiedzią o treści „email”
Napis „Podaj hasło:”, a pod nim pole edycyjne do wprowadzenia hasła, realizuje ukrywanie hasła jak na obrazach 1a i 1b
Napis „Powtórz hasło:”, a pod nim pole edycyjne do wprowadzenia hasła, realizuje ukrywanie hasła jak na obrazach 1a i 1b
Przycisk o treści „ZATWIERDŹ”, jest on wyśrodkowany
Obszar do wyświetlania komunikatów, jest on wyśrodkowany
Działanie aplikacji
Po wybraniu przycisku ZATWIERDŹ jest sprawdzane:
Czy e-mail zawiera znak @
Czy podane hasło jest równe powtórzonemu hasłu
W obszarze do wyświetlania komunikatów pojawia się napis:
Na początku działania aplikacji: „Autor”, dalej wstawiony numer PESEL zdającego
Po zatwierdzeniu, gdy e-mail jest niepoprawny: „Nieprawidłowy adres e-mail”
Po zatwierdzeniu, gdy hasła się różnią: „Hasła się różnią”
Po zatwierdzeniu, gdy nie wystąpiły błędy: „Witaj <e-mail>”, gdzie <e-mail> oznacza aktualnie wprowadzony adres e-mail
Założenia aplikacji
Interfejs użytkownika zapisany za pomocą języka znaczników wspieranego w danym środowisku (np. XAML, XML)
Zastosowany typ rozkładu liniowy (Linear / Stack lub inny o tej idei)
Zastosowany kolor tła dla napisu „Rejestruj konto”: Teal (#008080), zgodnie z Obrazem 1a
Zastosowany kolory czcionki: czarny i biały, zgodnie z Obrazem 1a
Czcionka napisu „Rejestruj konto” jest wizualnie większa od pozostałych
Pola edycyjne są rozciągnięte na całą szerokość ekranu
Aplikacja powinna być zapisana czytelnie, z zasadami czystego formatowania kodu, stosować znaczące nazwy zmiennych i funkcji
Dokumentacja do programu wykonana zgodnie z wytycznymi z części III zadania egzaminacyjnego
Kod aplikacji (cały folder projektu) przygotuj do nagrania na płytę (skopiuj do folderu z numerem PESEL, do podfolderu mobilna).
Część III. Dokumentacja utworzonych aplikacji
Wykonaj dokumentację aplikacji utworzonych podczas egzaminu. W kodzie źródłowym aplikacji konsolowej utwórz nagłówek metody sortującej i szukającej, według wzoru umieszczonego w listingu 1. Nagłówek powinien znaleźć się w kodzie źródłowym nad metodą. W miejscu nawiasów <> należy podać nazwę funkcji, nazwy parametrów (lub słowo „brak”) oraz zwięzłe informacje (kilka słów) – zgodnie ze wzorcem. W miejscu autor należy podać swój numer PESEL
Listing 1. Wzór dokumentacji funkcji
Wykonaj zrzuty ekranu dokumentujące uruchomienie aplikacji. Zrzuty powinny obejmować cały obszar ekranu z widocznym paskiem zadań. Jeżeli aplikacja uruchamia się, na zrzucie należy umieścić okno z wynikiem działania programu oraz otwarte środowisko programistyczne z projektem. Jeżeli aplikacja nie uruchamia się z powodu błędów kompilacji, należy na zrzucie umieścić okno ze spisem błędów i widocznym otwartym środowiskiem programistycznym. Wymagane zrzuty ekranu:
z aplikacji konsolowej – konsola.jpg
z aplikacji mobilnej – mobilna.jpg
W edytorze tekstu pakietu biurowego utwórz plik z dokumentacją i nazwij go egzamin.
Dokument powinien zawierać podpisane zrzuty ekranu oraz zapisane informacje:
nazwę systemu operacyjnego, na którym pracował zdający
nazwy środowisk programistycznych, z których zdający korzystał na egzaminie
nazwy języków programowania użytych podczas tworzenia aplikacji
nazwę emulowanego urządzenia lub systemu, na którym uruchomiono aplikację mobilną
opcjonalnie komentarz do wykonanej pracy
Dokumentacja powinna się znajdować w podfolderze dokumentacja
UWAGA!
Nagraj płytę z rezultatami pracy. W folderze z numerem PESEL powinny się znajdować podfoldery dokumentacja, konsola, mobilna. W folderze dokumentacja powinny znaleźć się pliki: konsola.jpg, mobilna.jpg, egzamin. W folderze konsola: cały projekt aplikacji konsolowej. W folderze mobilna: cały projekt aplikacji mobilnej, ewentualnie inne przygotowane pliki.
Po nagraniu płyty sprawdź poprawność nagrania. Opisz płytę swoim numerem PESEL i pozostaw na stanowisku, zapakowaną w pudełku wraz z arkuszem egzaminacyjnym.
Czas przeznaczony na wykonanie zadania wynosi 180 minut.
Ocenie będą podlegać 4 rezultaty
Implementacja, kompilacja, uruchomienie programu
Aplikacja konsolowa
Aplikacja mobilna
Dokumentacja aplikacji.
Otwórz Visual Studio 2022.
Kliknij "Utwórz nowy projekt".
Wybierz "Aplikacja konsolowa (.NET 8)" i kliknij Dalej.
Nazwij projekt np. SortowanieWybor.
Wybierz lokalizację folderu: PESEL/konsola/.
Kliknij Utwórz.
Twój kod programu 🕷️
Kliknij F5 lub przycisk Uruchom.
Wpisz 10 liczb całkowitych.
Sprawdź, czy tablica została poprawnie posortowana malejąco.
W Visual Studio 2022 kliknij "Nowy projekt".
Wybierz ".NET MAUI App" i kliknij Dalej.
Nazwij projekt RejestracjaKonta.
Wybierz lokalizację PESEL/mobilna/.
Kliknij Utwórz.
Zamień zawartość pliku MainPage.xaml na:
Twój kod programu 🕷️
Edytuj MainPage.xaml.cs:
Twój kod programu 🕷️
Otwórz Android Emulator w Visual Studio.
Kliknij Uruchom i sprawdź działanie formularza.
Wykonaj zrzuty ekranu:
konsola.jpg – wynik działania aplikacji konsolowej.
mobilna.jpg – działanie aplikacji mobilnej.
Otwórz Word / LibreOffice Writer.
Stwórz plik egzamin.docx i dodaj:
Nazwa systemu: Windows 11.
Środowisko: Visual Studio 2022.
Język: C#.
Emulator: Android Oreo / Nexus 5X API 29. lub inny w jakim wykonujecie zadanie
Zrzuty ekranu.
Komentarz (opcjonalny).
Zapisz dokument w PESEL/dokumentacja/.
Gratulacje! Zadanie wykonane. 🚀
Oznaczenie: INF.04-01-22.06-SG Limit czasu: 150 minut
UWAGA!
Katalog z rezultatami pracy oraz płytę należy opisać numerem, którym został podpisany arkusz, czyli numerem PESEL lub w przypadku jego braku numerem paszportu.
Wykonaj aplikację konsolową oraz mobilną według wskazań. Wykonaj dokumentację do aplikacji konsolowej, zgodnie z opisem w części III instrukcji do zadania. W tym celu zaloguj się na konto Egzamin bez hasła.
Utwórz folder i nazwij go swoim numerem. W folderze utwórz podfoldery: konsola, mobilna, dokumentacja. Po wykonaniu każdej aplikacji, jej pełny kod (cały folder projektu) spakuj do archiwum. Następnie pozostaw w folderze jedynie pliki źródłowe, których treść modyfikowałeś, plik uruchomieniowy, jeśli jest to możliwe oraz spakowane archiwum.
Część I. Aplikacja konsolowa
Napisz program implementujący algorytm przeszukiwania tablicy z wartownikiem. Opis algorytmu znajduje się w ramce.
By odnaleźć element x podejmiemy następujące kroki:
na końcu tablicy (pod indeksem n+1) wstawimy szukany element x - będzie to nasz wartownik, w przypadku, gdy nie znajdziemy go nigdzie indziej w tablicy, zabezpieczy nas on przed wyjściem poza tablicę
przejdziemy po kolejnych elementach tablicy, tak długo aż nie znajdziemy szukanego elementu
w momencie znalezienia szukanego elementu x sprawdzamy, który jest to element tablicy? Jeżeli jest to ostatni element tablicy (n+1) to trafiliśmy na naszego wartownika i oznacza to, że w tablicy nie było szukanego elementu x, w przeciwnym razie element x został odnaleziony
Założenia do programu:
Program wykonywany w konsoli
Zastosowany obiektowy język programowania zgodny z zainstalowanym na stanowisku egzaminacyjnym: C++ lub C#, lub Java, lub Python
Przeszukiwana jest minimum 50 elementowa tablica liczb całkowitych wypełniona wartościami pseudolosowymi z zakresu od 1 do 100
Wyszukiwane jest pierwsze wystąpienie elementu w tablicy
Wypełnianie tablicy i przeszukiwanie jest realizowane w oddzielnych funkcjach / metodach. Funkcja przeszukująca zwraca indeks odnalezionego elementu
Wartość do wyszukania jest pobierana z klawiatury
Po przeszukaniu tablicy na ekranie wyświetlana jest zawartość tablicy (liczby oddzielone przecinkami) oraz indeks, pod którym odszukano wartość lub w przypadku jej braku – stosowny komunikat
Program powinien podejmować zrozumiałą komunikację z użytkownikiem, dane wprowadzane i wyprowadzane powinny być opatrzone zrozumiałym opisem
Program powinien być zapisany czytelnie, z zachowaniem zasad czystego formatowania kodu, należy stosować znaczące nazwy zmiennych i funkcji
Program główny powinien zawierać test działania aplikacji
Podejmij próbę kompilacji i uruchomienia aplikacji. Informacje dotyczące dokumentacji i zrzutów ekranowych umieszczono w części III zadania.
Kod aplikacji przygotuj do nagrania na płytę. W podfolderze konsola powinno znaleźć się archiwum całego projektu o nazwie konsola.zip, plik z kodem źródłowym programu oraz plik uruchomieniowy, jeżeli istnieje.
Część II. Aplikacja mobilna
Wykonaj aplikację mobilną za pomocą środowiska programistycznego dostępnego na stanowisku egzaminacyjnym oraz uruchom ją w dostępnym emulatorze systemu mobilnego. Aplikacja jest fragmentem programu do przeglądania ofert turystycznych. Do wykonania aplikacji należy wykorzystać obraz z archiwum domek.zip znajdującego się na pulpicie konta Egzamin i zabezpieczonego hasłem: !Turystyk@
Obraz 1a. Aplikacja AndroidStudio, stan początkowy. Emulacja Nexus 5X API 29 x86
Obraz 1b. Aplikacja MS Visual Studio, zachowanie aplikacji: 5 razy wciśnięto „POLUB”. Emulacja Android Oreo
Na obrazie 1a przedstawiono stan po uruchomieniu aplikacji mobilnej. W zależności od zastosowanego środowiska programistycznego oraz emulowanego systemu wynik końcowy może nieznacznie się różnić od przedstawionego. Na obrazie 1b przedstawiono zachowanie aplikacji: 5 razy wciśnięto przycisk „POLUB” i w efekcie status pod przyciskami wyświetla tekst „5 polubień”.
Elementy aplikacji:
Tytuł o treści: „Domek w górach”
Obraz o nazwie obraz.jpg wypakowany z archiwum
Trzy przyciski o treści: „POLUB”, „USUŃ”, „ZAPISZ” umiejscowione obok siebie
Napis o treści „0 polubień”
Linia horyzontalna
Napis o treści „Opis”
Napis o treści „Odwiedź komfortowy domek w Sudetach, blisko do szlaków turystycznych”
Działanie aplikacji:
Aplikacja implementuje licznik polubień, który w stanie początkowym aplikacji jest równy 0, następnie jego stan jest:
inkrementowany po wciśnięciu przycisku „POLUB”
dekrementowany po wciśnięciu przycisku „USUŃ”. Licznik nie może być niższy niż 0
Stan licznika jest wyświetlany pod przyciskami, w formie napisu „<x> polubień”, gdzie <x> oznacza aktualną wartość licznika
Założenia aplikacji:
Interfejs użytkownika zapisany za pomocą języka znaczników wspieranego w danym środowisku (np. XAML, XML)
Zastosowany typ rozkładu liniowy wertykalny (Linear / Stack lub inny o tej idei) z zagłębionym rozkładem liniowym horyzontalnym dla przycisków
Margines wewnętrzny górny dla całej strony lub rozkładu wertykalnego: 20 px (lub dp)
Kolor tła przycisków i rozkładu, w którym się znajdują: Teal (#008080), zgodnie z Obrazem 1a
Kolory czcionki: biały dla przycisków oraz Gray (#808080) dla napisu „Odwiedź...”, zgodnie z Obrazem 1a
Czcionka tytułu ma rozmiar największy spośród użytych w aplikacji
Czcionka napisu „Opis” jest pogrubiona
Napis o liczbie polubień jest wyrównany do prawej
Obraz wypełnia całą szerokość strony (zależnie od zastosowanego aspektu może być automatycznie obcięty przez emulator – zobacz obraz 1b)
Linia horyzontalna jest koloru Gray (#808080), dopuszcza się również prostokąt o wysokości 1
Aplikacja powinna być zapisana czytelnie, z zachowaniem zasad czystego formatowania kodu, należy stosować znaczące nazwy zmiennych i funkcji
Podejmij próbę kompilacji i emulacji. Informacje dotyczące dokumentacji i zrzutów ekranowych umieszczono w części III zadania.
Kod aplikacji przygotuj do nagrania na płytę. W podfolderze mobilna powinno znaleźć się archiwum całego projektu o nazwie mobilna.zip, plik źródłowy interfejsu użytkownika (XAML lub XML) oraz plik źródłowy kodu skojarzonego z interfejsem użytkownika.
Część III. Dokumentacja aplikacji
Wykonaj dokumentację do aplikacji utworzonych na egzaminie. W kodzie źródłowym aplikacji konsolowej utwórz nagłówek funkcji przeszukującej, według wzoru zgodnie z listingiem 1. Nagłówek powinien znaleźć się w kodzie źródłowym nad funkcją. W miejscu nawiasów <> należy podać nazwę funkcji, nazwy argumentów wraz z krótkim opisem, typ zwracany wraz z krótkim opisem, krótki opis zawierający przynajmniej nazwę algorytmu. Gdy funkcja nie ma argumentów – zapisać „brak”. W miejscu autor należy podać swój numer.
UWAGA!
Dokumentację umieścić w komentarzu (wieloliniowym lub kilku jednoliniowych). Znajdujący się w listingu 1 wzór dokumentacji jest bez znaków początku i końca komentarza, gdyż te są różne dla różnych języków programowania.
Listing 1. Wzór dokumentacji funkcji
Wykonaj zrzuty ekranu dokumentujące uruchomienie aplikacji utworzonych podczas egzaminu. Zrzuty powinny obejmować cały obszar ekranu monitora z widocznym paskiem zadań.
Jeżeli aplikacja uruchamia się, na zrzucie należy umieścić okno z wynikiem działania programu oraz otwarte środowisko programistyczne z projektem lub okno terminala z kompilacją projektu.
Jeżeli aplikacja nie uruchamia się z powodu błędów kompilacji, należy na zrzucie umieścić okno ze spisem błędów i widocznym otwartym środowiskiem programistycznym.
Wykonać należy tyle zrzutów ile interakcji podejmuje aplikacja. Wymagane zrzuty ekranu:
Aplikacja konsolowa – dowolna liczba zrzutów nazwanych konsola1, konsola2 ...
Aplikacja mobilna – dowolna liczba zrzutów nazwanych mobile1, mobile2 ... (np. stan początkowy, po wciśnięciu przycisku polubień)
W edytorze tekstu pakietu biurowego utwórz plik z dokumentacją i nazwij go egzamin. Dokument powinien zawierać podpisane zrzuty ekranu oraz zapisane informacje:
Nazwę systemu operacyjnego, na którym pracował zdający
Nazwy środowisk programistycznych, z których zdający korzystał na egzaminie
Nazwy języków programowania
Nazwa emulatora systemu mobilnego
Zrzuty ekranu i dokument umieść w podfolderze dokumentacja.
UWAGA!
Nagraj płytę z rezultatami pracy. W folderze z numerem zdającego powinny się znajdować podfoldery: konsola, mobilna, dokumentacja. W folderze dokumentacja: pliki ze zrzutami oraz plik egzamin. W folderze konsola: spakowany cały projekt aplikacji konsolowej, pliki z kodem źródłowym, opcjonalnie plik uruchomieniowy. W folderze mobilna: spakowany cały projekt aplikacji mobilnej, pliki ze źródłami interfejsu i logiki.
Po nagraniu płyty sprawdź poprawność nagrania. Opisz płytę swoim numerem i pozostaw na stanowisku, zapakowaną w pudełku wraz z arkuszem egzaminacyjnym.
Czas przeznaczony na wykonanie zadania wynosi 180 minut.
Ocenie będą podlegać 4 rezultaty
Implementacja, kompilacja, uruchomienie programu
Aplikacja konsolowa
Aplikacja mobilna
Dokumentacja aplikacji.
Otwórz Visual Studio 2022.
Kliknij "Utwórz nowy projekt".
Wybierz "Aplikacja konsolowa (.NET 8)".
Nazwij projekt np. "PrzeszukiwanieTablicy".
Wybierz folder PESEL/konsola/ jako miejsce zapisania projektu.
Kliknij Utwórz.
Jest to optymalizacja liniowego wyszukiwania w analizie. Polega na dodaniu wartości ( dodatkowego elementu na końcu), który powoduje wyłączenie zdarzenia w każdej iteracji.
Wstawiamy szukany element xna koniec tablicy (poza jej zakres).
Przeszukujemy tablicę bez konieczności sprawdzania zakresu , co upraszcza kod.
Jeśli znaleźliśmy x, sprawdzamy, czy nie trafiliśmy na wartownika .
W Visual Studio 2022 kliknij "Nowy projekt".
Wybierz ".NET MAUI App" i kliknij Dalej.
Nazwij projekt TurystykaApp.
Wybierz folder PESEL/mobilna/.
Kliknij Utwórz.
Otwórz Android Device Manager.
Uruchom emulator Androida (np. Pixel 5 API 30).
Kliknij Uruchom w Visual Studio.
Zrzuty ekranu:
konsola1.jpg, konsola2.jpg – aplikacja konsolowa.
mobile1.jpg, mobile2.jpg – aplikacja mobilna.
Utwórz plik dokumentacji:
Otwórz Word / LibreOffice Writer.
Nazwij plik "egzamin.docx".
Dodaj:
System operacyjny: np. Windows 11.
Środowisko programistyczne: Visual Studio 2022.
Język programowania: C#.
Emulator: Android Oreo / Nexus 5X API 29.
Zrzuty ekranu.
Zapisz dokument w folderze PESEL/dokumentacja/.
using System;
namespace PrzeszukiwanieTablicy
{
class Program
{
static void Main()
{
int[] tablica = new int[51]; // Tablica 50 elementowa + wartownik
Random rand = new Random();
for (int i = 0; i < 50; i++)
{
tablica[i] = rand.Next(1, 101);
}
Console.WriteLine("Tablica liczb:");
Console.WriteLine(string.Join(", ", tablica[..50]));
Console.Write("Podaj liczbę do wyszukania: ");
int x = int.Parse(Console.ReadLine());
int wynik = Wyszukaj(tablica, x);
if (wynik == -1)
Console.WriteLine("Element nie został znaleziony.");
else
Console.WriteLine($"Element {x} znaleziony na indeksie: {wynik}");
}
static int Wyszukaj(int[] tablica, int x)
{
tablica[50] = x; // Wartownik
int i = 0;
while (tablica[i] != x)
{
i++;
}
return (i == 50) ? -1 : i;
}
}
}
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TurystykaApp.MainPage">
<VerticalStackLayout Padding="20">
<Label Text="Domek w górach" FontSize="24" HorizontalOptions="Center" />
<Image Source="obraz.jpg" Aspect="AspectFill" WidthRequest="300" HeightRequest="200" />
<HorizontalStackLayout BackgroundColor="#008080" Padding="10">
<Button Text="POLUB" Clicked="OnPolubClicked" TextColor="White" />
<Button Text="USUŃ" Clicked="OnUsunClicked" TextColor="White" />
<Button Text="ZAPISZ" TextColor="White" />
</HorizontalStackLayout>
<Label x:Name="LicznikPolubien" Text="0 polubień" HorizontalOptions="End" />
<BoxView HeightRequest="1" BackgroundColor="Gray" />
<Label Text="Opis" FontAttributes="Bold" />
<Label Text="Odwiedź komfortowy domek w Sudetach, blisko do szlaków turystycznych" TextColor="Gray" />
</VerticalStackLayout>
</ContentPage>
namespace TurystykaApp;
public partial class MainPage : ContentPage
{
private int licznik = 0;
public MainPage()
{
InitializeComponent();
}
private void OnPolubClicked(object sender, EventArgs e)
{
licznik++;
LicznikPolubien.Text = $"{licznik} polubień";
}
private void OnUsunClicked(object sender, EventArgs e)
{
if (licznik > 0)
licznik--;
LicznikPolubien.Text = $"{licznik} polubień";
}
}
konsola + webowe
Oznaczenie: INF.04-02-22.06-SG Limit czasu: 150 minut
UWAGA!
Katalog z rezultatami pracy oraz płytę należy opisać numerem, którym został podpisany arkusz, czyli numerem PESEL lub w przypadku jego braku numerem paszportu.
Wykonaj aplikację konsolową oraz webową według wskazań. Wykonaj dokumentację do aplikacji konsolowej, zgodnie z opisem w części III instrukcji do zadania. W tym celu zaloguj się na konto Egzamin bez hasła.
Utwórz folder i nazwij go swoim numerem. W folderze utwórz podfoldery: konsola, web, testy. Po wykonaniu każdej aplikacji, jej pełny kod (cały folder projektu) spakuj do archiwum. Następnie pozostaw w podfolderze jedynie pliki źródłowe, których treść modyfikowałeś, plik uruchomieniowy, jeśli jest to możliwe oraz spakowane archiwum. Zrzuty ekranu dokumentujące uruchomienie obu aplikacji umieść w folderze testy.
Część I. Aplikacja konsolowa
Korzystając z mechanizmów programowania obiektowego zaprojektuj część logiki systemu forum użytkowników. Zaimplementuj klasę o nazwie osoba z konstruktorami, metodą i obsługą pola statycznego.
Założenia klasy:
Zastosowano obiektowy język programowania zgodny z zainstalowanym na stanowisku egzaminacyjnym: C++ lub C#, lub Java, lub Python.
Klasa Osoba zawiera:
Dwa pola: numeryczne id oraz tekstowe imię osoby. Dostęp do obu pól ma jedynie klasa. W przypadku późniejszego rozszerzenia klasy, klasy potomne nie mają dostępu do tych pól.
Ogólnie dostępne pole statyczne zliczające liczbę instancji klasy, początkowo wypełnione wartością 0.
Trzy konstruktory:
bezparametrowy, ustawia wartości 0 i pusty dla pól
z dwoma parametrami, które przekazują wartości id i imienia
kopiujący
Każdy z konstruktorów dodatkowo inkrementuje liczbę instancji klasy
Metodę do wypisania imienia obiektu klasy Osoba w postaci: „Cześć <argument>, mam na imię <imie>”, gdzie pole <argument> jest innym imieniem przekazanym jako parametr wejściowy metody. Jeżeli w obiekcie nie wypełniono wartości pola z imieniem wyświetlany jest komunikat „Brak danych”
UWAGA!
W języku Python, zamiast przeciążenia konstruktorów, należy utworzyć konstruktor z dwoma parametrami o wartościach domyślnych (0, pusty napis), który będzie zastępował konstruktor bezparametrowy oraz konstruktor z dwoma parametrami. Następnie zaimplementować metodę kopiującą dane z jednego obiektu do drugiego.
Program powinien być zapisany czytelnie, z zachowaniem zasad czystego formatowania kodu, należy stosować znaczące nazwy pól i metod.
Do klasy należy dołączyć dokumentację oraz testy w postaci programu głównego. Testy zostały opisane w części III zadania egzaminacyjnego.
Kod aplikacji przygotuj do nagrania na płytę. W podfolderze konsola powinno znaleźć się archiwum całego projektu o nazwie konsola.zip, plik z kodem źródłowym klasy oraz plik uruchomieniowy, jeżeli istnieje.
Część II. Aplikacja Web
Wykonaj aplikację internetową typu front-end obsługującą zapisy na kursy z zastosowaniem dostępnego na stanowisku egzaminacyjnym frameworka Angular lub biblioteki React. Zastosuj bibliotekę Bootstrap do zdefiniowania stylu formularza.
Obraz 1a. Aplikacja framework Angular
Obraz 1b. Aplikacja React.j
Na obrazach 1a i 1b przedstawiono działanie aplikacji przygotowanej w środowisku Angular i React.js, stan po wybraniu przycisku „Zapisz do kursu”. W konsoli widoczne wyświetlenie imienia i nazwiska oraz nazwy kursu na podstawie danych wprowadzonych do formularza
Założenia aplikacji:
Aplikacja składa się z jednego komponentu
Danymi komponentu jest tablica z nazwami kursów, o elementach: "Programowanie w C#", "Angular dla początkujących", "Kurs Django". Dla uproszczenia tablica może być zdefiniowana jako pole komponentu. Należy założyć, że tablica w przyszłości może się zmienić, co będzie miało wpływ na zachowanie i wygląd aplikacji.
Komponent wyświetla:
Nagłówek drugiego stopnia o treści: „Liczba kursów: <liczba>”, gdzie <liczba> oznacza wielkość tablicy z nazwami kursów
Listę numerowaną generowaną automatycznie dla wszystkich elementów tablicy, niezależnie od jej wymiaru
Formularz składający się z:
pola edycyjnego i jego etykiety o treści „Imię i nazwisko:”
edycyjnego pola numerycznego i jego etykiety o treści „Numer kursu:”
przycisku „Zapisz do kursu”
Aplikacja w stanie początkowym wyświetla puste pola formularza
Elementy formularza są formatowane zgodnie z obrazem 1a lub 1b za pomocą stylów biblioteki Bootstrap. Do budowy szablonu HTML należy wykorzystać pomoc zamieszczoną w Tabeli 1. Należy zastosować znaczące nazwy dla identyfikatorów pól formularza
Po wybraniu przycisku formularza jest generowane zdarzenie zatwierdzenia formularza, które wyświetla w konsoli przeglądarki:
Wartość wpisaną w pierwszym polu formularza
Nazwę kursu odpowiadającą numerowi wpisanemu w drugie pole formularza, gdy kurs o takim numerze istnieje. W przeciwnym wypadku wyświetla komunikat "Nieprawidłowy numer kursu"
Aplikacja powinna być zapisana czytelnie, z zachowaniem zasad czystego formatowania kodu, należy stosować znaczące nazwy zmiennych i funkcji
Dokumentacja do programu wykonana zgodnie z wytycznymi z części III zadania egzaminacyjnego
Kod aplikacji przygotuj do nagrania na płytę. W podfolderze web powinno znaleźć się archiwum całego projektu o nazwie web.zip oraz pliki z kodem źródłowym, które były modyfikowane.
Część III. Testy utworzonych aplikacji
Wykonaj testy aplikacji konsolowej oraz dokumentację do aplikacji utworzonych na egzaminie.
W podfolderze konsola w programie głównym aplikacji konsolowej należy sprawdzić działanie klasy poprzez, kolejno:
Wyświetlenie komunikatu „Liczba zarejestrowanych osób to <licznik>”, gdzie <licznik> jest wartością pobraną z pola statycznego klasy
Utworzenie obiektu za pomocą konstruktora bezparametrowego
Utworzenie obiektu za pomocą konstruktora z dwoma parametrami. Dane obiektu wprowadzane z klawiatury
Utworzenie obiektu za pomocą konstruktora kopiującego (w Python konstruktora bezparametrowego i metody kopiującej). Obiekt z wypełnionymi polami jest źródłem kopiowania danych
Wywołanie metody do wypisania imienia z parametrem wejściowym równym „Jan” dla wszystkich utworzonych obiektów
Ponowne wyświetlenie komunikatu „Liczba zarejestrowanych osób to <licznik>”, gdzie <licznik> jest wartością pobraną z pola statycznego klasy
Wykonaj zrzuty ekranu dokumentujące uruchomienie aplikacji utworzonych podczas egzaminu. Zrzuty powinny obejmować cały obszar ekranu monitora z widocznym paskiem zadań.
Jeżeli aplikacja uruchamia się, na zrzucie należy umieścić okno z wynikiem działania programu oraz otwarte środowisko programistyczne z projektem lub okno terminala z kompilacją projektu.
Jeżeli aplikacja nie uruchamia się z powodu błędów kompilacji, należy na zrzucie umieścić okno ze spisem błędów i widocznym otwartym środowiskiem programistycznym.
Wykonać należy tyle zrzutów ile interakcji podejmuje aplikacja. Wymagane zrzuty ekranu:
Aplikacja konsolowa – dowolna liczba zrzutów nazwanych konsola1, konsola2 ...
Aplikacja web – dowolna liczba zrzutów nazwanych web1, web2 ... (np. stan początkowy, po wypełnieniu pól, po zatwierdzeniu konsola przeglądarki, gdy w drugim polu formularza jest prawidłowy numer oraz gdy jest nieprawidłowy numer kursu)
W edytorze tekstu pakietu biurowego utwórz plik z dokumentacją i nazwij go egzamin. Dokument powinien zawierać informacje:
Nazwę systemu operacyjnego, na którym pracował zdający
Nazwy środowisk programistycznych, z których zdający korzystał na egzaminie
Nazwy języków programowania / frameworków / bibliotek użytych podczas tworzenia aplikacji
Zrzuty ekranu i dokument umieść w folderze o nazwie testy.
UWAGA!
Nagraj płytę z rezultatami pracy. W folderze z numerem zdającego powinny się znajdować podfoldery: konsola, testy, web. W folderze konsola: spakowany cały projekt aplikacji konsolowej, pliki z kodem źródłowym, opcjonalnie plik uruchomieniowy. W folderze testy: pliki ze zrzutami oraz plik egzamin. W folderze web: spakowany cały projekt aplikacji web, pliki modyfikowane przez zdającego.
Po nagraniu płyty sprawdź poprawność nagrania. Opisz płytę swoim numerem i pozostaw na stanowisku, zapakowaną w pudełku wraz z arkuszem egzaminacyjnym.
Czas przeznaczony na wykonanie zadania wynosi 180 minut.
Ocenie będą podlegać 4 rezultaty:
implementacja, kompilacja, uruchomienie programu
aplikacja konsolowa
aplikacja web
testy aplikacji.
Tabela 1. Wybrane elementy frameworka Angular, biblioteki React.js i biblioteki Bootstrap - przykłady
Zainstaluj Visual Studio 2022
Pobierz Visual Studio 2022 ze strony Microsoft.
Podczas instalacji wybierz komponenty:
.NET Desktop Development
ASP.NET and Web Development
Node.js development (dla Angulara)
Po instalacji uruchom Visual Studio 2022.
Zainstaluj Angular
Otwórz terminal w Visual Studio i wpisz:
npm install -g @angular/cli
Sprawdź instalację:
ng version
Utwórz nowy projekt
Otwórz Visual Studio 2022.
Wybierz Create a new project → Console App (.NET).
Nazwij projekt Konsola i wybierz lokalizację w folderze konsola.
Kliknij Create.
Implementacja klasy Osoba
using System;
class Osoba
{
private int id;
private string imie;
public static int Licznik = 0;
// Konstruktor bezparametrowy
public Osoba()
{
id = 0;
imie = "";
Licznik++;
}
// Konstruktor z parametrami
public Osoba(int id, string imie)
{
this.id = id;
this.imie = imie;
Licznik++;
}
// Konstruktor kopiujący
public Osoba(Osoba innaOsoba)
{
this.id = innaOsoba.id;
this.imie = innaOsoba.imie;
Licznik++;
}
public void Powitanie(string argument)
{
if (string.IsNullOrEmpty(imie))
Console.WriteLine("Brak danych");
else
Console.WriteLine($"Cześć {argument}, mam na imię {imie}");
}
}
class Program
{
static void Main()
{
Console.WriteLine($"Liczba zarejestrowanych osób to {Osoba.Licznik}");
Osoba o1 = new Osoba();
Osoba o2 = new Osoba(1, "Adam");
Console.Write("Podaj ID: ");
int id = int.Parse(Console.ReadLine());
Console.Write("Podaj imię: ");
string imie = Console.ReadLine();
Osoba o3 = new Osoba(id, imie);
Osoba o4 = new Osoba(o3);
o1.Powitanie("Jan");
o2.Powitanie("Jan");
o3.Powitanie("Jan");
o4.Powitanie("Jan");
Console.WriteLine($"Liczba zarejestrowanych osób to {Osoba.Licznik}");
}
}
Po utworzeniu projektu w Visual Studio 2022 struktura plików wygląda następująco:
web-app/
├── src/
│ ├── app/
│ │ ├── kursy/
│ │ │ ├── kursy.component.ts <-- Logika komponentu
│ │ │ ├── kursy.component.html <-- Widok (HTML)
│ │ │ ├── kursy.component.css <-- Style
│ │ ├── app.module.ts <-- Deklaracja komponentu
│ ├── assets/
│ ├── environments/
│ ├── index.html <-- Strona główna aplikacji
│ ├── main.ts <-- Punkt wejścia aplikacji
├── angular.json <-- Konfiguracja projektu
├── package.json <-- Lista zależności
kursy.component.ts - Logika komponentu
kursy.component.html - Widok formularza
app.module.ts - Rejestracja komponentu
1. Edycja kursy.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-kursy',
templateUrl: './kursy.component.html',
styleUrls: ['./kursy.component.css']
})
export class KursyComponent {
kursy: string[] = ["Programowanie w C#", "Angular dla początkujących", "Kurs Django"];
imieNazwisko: string = "";
numerKursu: number | null = null;
zapiszDoKursu() {
if (this.numerKursu === null || this.imieNazwisko.trim() === "") {
console.log(" Błąd: Wprowadź poprawne imię i numer kursu!");
return;
}
const index = this.numerKursu - 1; // Przesunięcie numeru kursu (bo tablica zaczyna się od 0)
if (index >= 0 && index < this.kursy.length) {
console.log(` Zapisano: ${this.imieNazwisko} na kurs: ${this.kursy[index]}`);
} else {
console.log("Nieprawidłowy numer kursu");
}
}
}
2. Edycja kursy.component.html
<div class="container">
<h2>Liczba kursów: {{ kursy.length }}</h2>
<ol>
<li *ngFor="let kurs of kursy; let i = index">{{ i + 1 }}. {{ kurs }}</li>
</ol>
<div class="mb-3">
<label>Imię i nazwisko:</label>
<input type="text" class="form-control" [(ngModel)]="imieNazwisko" />
</div>
<div class="mb-3">
<label>Numer kursu:</label>
<input type="number" class="form-control" [(ngModel)]="numerKursu" />
</div>
<button class="btn btn-primary" (click)="zapiszDoKursu()">Zapisz do kursu</button>
</div>
3. Edycja app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; // ✅ DODAJ TEN IMPORT
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { KursyComponent } from './kursy/kursy.component'; // Sprawdź poprawność ścieżki
@NgModule({
declarations: [
AppComponent,
KursyComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule // ✅ DODAJ TO TUTAJ
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Uruchom aplikację:
ng serve
📌 O co chodzi w zadaniu?
Musisz stworzyć klasę Osoba, która będzie reprezentować użytkownika forum.
Każda osoba ma:
ID (identyfikator numeryczny)
Imię
Licznik instancji (statyczne pole zliczające liczbę obiektów Osoba)
Twoja klasa Osoba powinna pozwalać na różne sposoby tworzenia obiektów za pomocą trzech konstruktorów. Dodatkowo powinna mieć metodę PrzedstawSie(), która wyświetli imię użytkownika.
1️⃣ Dwa prywatne pola (id i imie) – przechowują dane o użytkowniku.
2️⃣ Statyczne pole liczbaInstancji – zlicza, ile obiektów Osoba zostało utworzonych.
3️⃣ Trzy konstruktory:
Bezparametrowy – domyślnie ustawia ID na 0, a imię na pusty string "".
Z dwoma parametrami – pozwala utworzyć obiekt, podając ID i imię.
Kopiujący – tworzy nową osobę, kopiując dane z innej. 4️⃣ Metoda PrzedstawSie(string argument), która:
Jeśli obiekt ma imię → wyświetla: "Cześć <argument>, mam na imię <imie>"
Jeśli imie jest puste → wyświetla: "Brak danych"
W programowaniu konstruktory pozwalają na elastyczne tworzenie obiektów.
Każdy z trzech konstruktorów ma inną funkcję:
👉 Jeśli użytkownik nie poda żadnych danych, to program przypisze domyślne wartości.
Przykład użycia:
csharp
KopiujEdytuj
Osoba osoba1 = new Osoba();
Wartości początkowe:
ini
KopiujEdytuj
id = 0
imie = ""
👉 Jeśli użytkownik poda ID i imię, to te wartości zostaną przypisane.
Przykład użycia:
csharp
KopiujEdytuj
Osoba osoba2 = new Osoba(101, "Grzegorz");
Wartości początkowe:
ini
KopiujEdytuj
id = 101
imie = "Grzegorz"
👉 Jeśli chcemy skopiować dane z innego obiektu.
Przykład użycia:
csharp
KopiujEdytuj
Osoba osoba3 = new Osoba(osoba2);
Wartości początkowe: (kopiowane z osoba2)
ini
KopiujEdytuj
id = 101
imie = "Grzegorz"
Wszystkie obiekty Osoba mają jedno wspólne pole liczbaInstancji, które zlicza liczbę utworzonych osób.
Za każdym razem, gdy tworzymy nowy obiekt, licznik się zwiększa.
Przykład działania:
csharp
KopiujEdytuj
Console.WriteLine($"Liczba zarejestrowanych osób to {Osoba.PobierzLiczbeInstancji()}");
Osoba osoba1 = new Osoba();
Console.WriteLine($"Liczba zarejestrowanych osób to {Osoba.PobierzLiczbeInstancji()}");
Osoba osoba2 = new Osoba(102, "Adam");
Console.WriteLine($"Liczba zarejestrowanych osób to {Osoba.PobierzLiczbeInstancji()}");
📌 Oczekiwany wynik:
css
KopiujEdytuj
Liczba zarejestrowanych osób to 0
Liczba zarejestrowanych osób to 1
Liczba zarejestrowanych osób to 2
Ta metoda ma dwa przypadki:
Jeśli imie jest ustawione → wyświetla "Cześć <argument>, mam na imię <imie>".
Jeśli imie jest puste → wyświetla "Brak danych".
Przykłady działania:
csharp
KopiujEdytuj
Osoba osoba1 = new Osoba();
osoba1.PrzedstawSie("Kamil");
// Wynik: "Brak danych"
Osoba osoba2 = new Osoba(102, "Adam");
osoba2.PrzedstawSie("Marek");
// Wynik: "Cześć Marek, mam na imię Adam"