Lekcja 11. Menu, paski narzędzi i menu kontekstowe
ŚredniPo co się tego uczymy?
System menu to jeden z elementów wymienionych wprost w podstawie programowej (INF.04.5.3). Prawie każda aplikacja desktopowa ma pasek menu na górze (Plik, Edycja, Widok...), często też pasek narzędzi z ikonami i menu kontekstowe pod prawym przyciskiem myszy — te trzy elementy razem tworzą profesjonalnie wyglądający, wygodny w obsłudze interfejs.
Teoria
Menu (<Menu>) to klasyczny pasek menu znany z niemal każdego programu — składa się z pozycji głównych (MenuItem), z których każda może mieć rozwijaną listę podpozycji, kolejnych zagnieżdżonych podmenu, separatory (Separator) oddzielające grupy opcji, a nawet skróty klawiszowe wyświetlane obok nazwy (InputGestureText="Ctrl+S") — choć samo wyświetlenie tekstu skrótu to co innego niż jego faktyczne działanie (to trzeba obsłużyć osobno przez tzw. KeyBinding).
ToolBar (pasek narzędzi) to poziomy pasek z przyciskami — zwykle z samymi ikonami zamiast tekstu, dla szybkiego dostępu do najczęściej używanych funkcji (Nowy, Zapisz, Drukuj). Kontener ToolBarTray pozwala zgrupować kilka pasków narzędzi i przeciągać je w różne miejsca okna.
ContextMenu (menu kontekstowe) pojawia się po kliknięciu prawym przyciskiem myszy na dany element — przypisuje się je do właściwości ContextMenu dowolnej kontrolki. Typowy przykład: kliknięcie prawym przyciskiem na element listy pokazuje opcje "Edytuj", "Usuń", "Kopiuj".
Wszystkie trzy działają na tej samej zasadzie co przyciski z wcześniejszej lekcji — każda pozycja menu/przycisk na pasku ma atrybut Click="NazwaMetody" podpięty do metody w code-behind.
Przykład z życia
Otwórz dowolny edytor tekstu na komputerze: pasek menu na górze (Plik, Edycja, Widok, Pomoc), pod nim pasek narzędzi z ikonami (Nowy, Otwórz, Zapisz, Drukuj), a kliknięcie prawym przyciskiem myszy na zaznaczonym tekście pokazuje menu kontekstowe z opcjami Kopiuj/Wklej/Wytnij. To dokładnie te trzy elementy z tej lekcji, użyte razem w jednej, znajomej aplikacji.
Kod (XAML)
<Window x:Class="MenuApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Edytor" Height="350" Width="500">
<DockPanel>
<!-- Pasek menu -->
<Menu DockPanel.Dock="Top">
<MenuItem Header="_Plik">
<MenuItem Header="_Nowy" Click="Nowy_Click" InputGestureText="Ctrl+N"/>
<MenuItem Header="_Zapisz" Click="Zapisz_Click" InputGestureText="Ctrl+S"/>
<Separator/>
<MenuItem Header="Za_mknij" Click="Zamknij_Click"/>
</MenuItem>
<MenuItem Header="_Edycja">
<MenuItem Header="_Kopiuj" Click="Kopiuj_Click"/>
<MenuItem Header="_Wklej" Click="Wklej_Click"/>
</MenuItem>
</Menu>
<!-- Pasek narzedzi -->
<ToolBar DockPanel.Dock="Top">
<Button Content="Nowy" Click="Nowy_Click"/>
<Button Content="Zapisz" Click="Zapisz_Click"/>
<Separator/>
<Button Content="Kopiuj" Click="Kopiuj_Click"/>
</ToolBar>
<!-- Obszar roboczy z menu kontekstowym pod prawym przyciskiem -->
<TextBox x:Name="ObszarTekstu" AcceptsReturn="True" TextWrapping="Wrap">
<TextBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Kopiuj" Click="Kopiuj_Click"/>
<MenuItem Header="Wklej" Click="Wklej_Click"/>
<MenuItem Header="Wyczysc" Click="Wyczysc_Click"/>
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
</DockPanel>
</Window>
Komentarz i wyjaśnienie kodu
Zwróć uwagę, że przyciski "Nowy", "Zapisz" i "Kopiuj" na pasku narzędzi (ToolBar) wywołują TE SAME metody (Nowy_Click, Zapisz_Click, Kopiuj_Click), co odpowiadające im pozycje w menu — to typowa, dobra praktyka: użytkownik może wykonać tę samą akcję na kilka sposobów (menu, pasek narzędzi, menu kontekstowe, czasem też skrót klawiszowy), a cała logika jest napisana raz, w jednym miejscu.
Podkreślenie przed literą w Header="_Plik" oznacza skrót klawiszowy Alt — naciśnięcie Alt+P otworzy to menu, litera "P" zostanie podkreślona wizualnie w interfejsie.
ContextMenu przypisany do TextBox.ContextMenu sprawia, że kliknięcie prawym przyciskiem myszy WEWNĄTRZ tego konkretnego pola tekstowego pokaże zdefiniowane tam opcje — inne kontrolki w oknie miałyby swoje własne (albo żadne) menu kontekstowe.
Ćwiczenie samodzielne
Utwórz projekt z powyższym XAML, dopisz puste metody obsługi (Nowy_Click, Zapisz_Click itd. — na razie wystarczy, że każda np. zmieni tytuł okna), uruchom i sprawdź, że menu, pasek narzędzi i menu kontekstowe wszystkie działają.
Zadania do pracy własnej
Dodaj do menu "Plik" nową pozycję "Zapisz jako..." z separatorem oddzielającym ją od reszty opcji.
Dodaj menu "Widok" z dwiema pozycjami typu przełącznik (
MenuItem IsCheckable="True") — "Pokaż pasek narzędzi" i "Pokaż pasek statusu" — które chowają/pokazują odpowiednie elementy interfejsu przez zmianę ichVisibility.Zbuduj prosty "eksplorator plików" z
ListBoxreprezentującym listę plików, gdzie kliknięcie prawym przyciskiem myszy na elemencie listy pokazuje menu kontekstowe z opcjami "Otwórz", "Zmień nazwę", "Usuń" — każda opcja powinna wypisywać w pasku statusu, którego pliku dotyczyła akcja (na podstawie zaznaczonego elementu).
Typowe błędy
Duplikowanie kodu zamiast wspólnej metody — jeśli przycisk na pasku narzędzi i pozycja menu robią to samo, powinny wywoływać JEDNĄ, wspólną metodę, a nie dwie kopie tego samego kodu (trudniej wtedy o pomyłkę przy późniejszej zmianie logiki).
Zbyt głębokie zagnieżdżanie podmenu — więcej niż 2-3 poziomy zagnieżdżenia menu utrudniają użytkownikowi znalezienie potrzebnej opcji.
Brak menu kontekstowego tam, gdzie użytkownik go oczekuje — np. w polu tekstowym bez własnego ContextMenu, WPF i tak pokaże domyślne menu systemowe (Kopiuj/Wklej), ale w innych kontrolkach (np. na elemencie listy) brak menu kontekstowego może być mylące.
Nawiązanie do egzaminu zawodowego
To realizacja fragmentu INF.04.5.3 dotyczącego "systemu menu" i okien aplikacji. Razem z lekcjami o kontrolkach i dialogach kompletuje to zestaw podstawowych elementów interfejsu wymaganych na egzaminie.