Aplikacje desktopowe · Menu

Menu, paski narzędzi i menu kontekstowe

Prawie każdy program ma pasek menu, pasek narzędzi z przyciskami i menu pod prawym przyciskiem myszy. Razem tworzą wygodny interfejs. Zbudujesz je tak, aby każda akcja była napisana raz i dostępna z kilku miejsc.

  • około 40 minut
  • WPF · Menu · ToolBar · ContextMenu
  • INF.04.5.3

Po tej lekcji: zbudować Menu z podmenu i separatorem, ToolBar i ContextMenu, podpiąć je pod wspólne metody oraz wyjaśnić, czym są klawisze dostępu (_) i InputGestureText.

Zacznijmy od edytora

Trzy drogi do jednej akcji

Otwórz dowolny edytor tekstu. Na górze jest pasek menu (Plik, Edycja, Widok), pod nim pasek narzędzi z ikonami (Nowy, Zapisz, Kopiuj), a prawy przycisk myszy na tekście pokazuje menu kontekstowe. To właśnie te trzy elementy z podstawy programowej INF.04.5.3.

Wszystkie trzy działają tak samo jak zwykły przycisk: pozycja ma atrybut Click wskazujący metodę w code-behind. Dzięki temu „Zapisz” z menu, z paska i ze skrótu to jedna metoda.

1 · Poznaj narzędzia

Menu, ToolBar i ContextMenu

Menupasek na górze

Składa się z MenuItem, które mogą mieć podpozycje, Separator rozdzielający grupy i skróty (InputGestureText).

Na przykład Plik, Edycja, Widok

ToolBarszybkie przyciski

Poziomy pasek przycisków (zwykle z ikonami). Kilka pasków zgrupujesz w ToolBarTray i przeciągniesz w inne miejsca.

Na przykład Nowy, Zapisz, Drukuj

ContextMenuprawy przycisk

Pojawia się po kliknięciu prawym przyciskiem. Przypisujesz je do właściwości ContextMenu konkretnej kontrolki.

Na przykład Kopiuj, Wklej, Wyczyść

Laboratorium · ćwiczenie w przeglądarce, do którego odsyłają rozgrzewki na końcu lekcji

2 · Sprawdź w działaniu

Ta sama metoda, trzy miejsca

Kliknij „Zapisz” w menu Plik, potem „Zapisz” na pasku narzędzi. Kliknij prawym przyciskiem w polu tekstu i wybierz „Wyczyść”. Dziennik po prawej pokaże, która metoda się wykonała i skąd przyszło zdarzenie. Przełącz w menu Widok pasek narzędzi.

Ta interakcja wymaga włączonego JavaScriptu.

Użytkownik wybiera drogę, a Ty piszesz logikę raz. Pasek narzędzi i menu kontekstowe tylko wskazują te same metody.

3 · Wygląd

MainWindow.xaml

Całe okno to DockPanel: menu i pasek narzędzi przypięte do góry, pasek statusu do dołu, a pole tekstowe wypełnia resztę.

MainWindow.xamlxaml
<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>
            <MenuItem Header="_Widok">
                <MenuItem x:Name="MenuPasekNarzedzi" Header="Pokaż pasek narzędzi"
                          IsCheckable="True" IsChecked="True" Click="Widok_Click" />
            </MenuItem>
        </Menu>

        <!-- Pasek narzędzi -->
        <ToolBar x:Name="PasekNarzedzi" DockPanel.Dock="Top">
            <Button Content="Nowy" Click="Nowy_Click" />
            <Button Content="Zapisz" Click="Zapisz_Click" />
            <Separator />
            <Button Content="Kopiuj" Click="Kopiuj_Click" />
        </ToolBar>

        <!-- Pasek statusu -->
        <StatusBar DockPanel.Dock="Bottom">
            <TextBlock x:Name="EtykietaStatus" Text="Gotowe" />
        </StatusBar>

        <!-- 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="Wyczyść" Click="Wyczysc_Click" />
                </ContextMenu>
            </TextBox.ContextMenu>
        </TextBox>
    </DockPanel>
</Window>
  1. Header="_Plik" Podkreślnik przed literą tworzy klawisz dostępu: Alt+P otwiera to menu.
  2. InputGestureText="Ctrl+S" Wyświetla skrót obok nazwy. To tylko napis. Prawdziwy skrót wymaga osobnej obsługi, np. KeyBinding.
  3. Separator Linia rozdzielająca grupy opcji, w menu i na pasku narzędzi.
  4. IsCheckable="True" Pozycja menu staje się przełącznikiem z ptaszkiem, a stan odczytasz z IsChecked.
  5. TextBox.ContextMenu Menu kontekstowe tylko tego pola tekstowego.

4 · Działanie

MainWindow.xaml.cs

Każda metoda obsługuje akcję bez wiedzy, skąd została wywołana. Dlatego tę samą metodę podpinasz pod menu, pasek i menu kontekstowe.

MainWindow.xaml.cscsharp
using System.Windows;

namespace MenuApp;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Nowy_Click(object sender, RoutedEventArgs e)
    {
        ObszarTekstu.Clear();
        EtykietaStatus.Text = "Nowy dokument";
    }

    private void Zapisz_Click(object sender, RoutedEventArgs e)
    {
        EtykietaStatus.Text = "Zapisano dokument";
    }

    private void Zamknij_Click(object sender, RoutedEventArgs e)
    {
        Close();
    }

    private void Kopiuj_Click(object sender, RoutedEventArgs e)
    {
        ObszarTekstu.Copy();
        EtykietaStatus.Text = "Skopiowano zaznaczenie";
    }

    private void Wklej_Click(object sender, RoutedEventArgs e)
    {
        ObszarTekstu.Paste();
        EtykietaStatus.Text = "Wklejono ze schowka";
    }

    private void Wyczysc_Click(object sender, RoutedEventArgs e)
    {
        ObszarTekstu.Clear();
        EtykietaStatus.Text = "Wyczyszczono";
    }

    private void Widok_Click(object sender, RoutedEventArgs e)
    {
        PasekNarzedzi.Visibility = MenuPasekNarzedzi.IsChecked ? Visibility.Visible : Visibility.Collapsed;
    }
}
  1. Nowy_Click, Zapisz_Click, Kopiuj_Click Wspólne dla wszystkich trzech źródeł.
  2. ObszarTekstu.Copy() i Paste() Gotowe metody TextBox do obsługi schowka.
  3. Widok_Click Czyta IsChecked z pozycji menu i ustawia widoczność paska narzędzi.
  4. MenuPasekNarzedzi.IsChecked ? Visible : Collapsed Operator warunkowy zamienia stan ptaszka na wartość Visibility.

5 · Ściągawka

Elementy menu i ich odpowiedniki w WinForms

WPFWindows FormsCo robi
Menu + MenuItemMenuStrip + ToolStripMenuItemPasek menu z pozycjami.
HeaderTextNapis pozycji menu. Znak _ (WPF) lub & (Forms) tworzy klawisz dostępu.
ToolBarToolStripPasek narzędzi.
ContextMenuContextMenuStripMenu pod prawym przyciskiem.
IsCheckable, IsCheckedCheckOnClick, CheckedPozycja menu jako przełącznik.
StatusBarStatusStripPasek statusu u dołu okna.
Na egzaminie zdarza się pytanie o odpowiednik w Windows Forms, więc warto znać oba nazewnictwa.

6 · Czego unikać

Trzy błędy w menu

Kopia kodu zamiast wspólnej metody
Tak nie
<MenuItem Header="Zapisz" Click="ZapiszMenu_Click" />
<Button Content="Zapisz" Click="ZapiszPasek_Click" />

Dwie metody z tym samym kodem. Zmiana logiki wymaga poprawek w dwóch miejscach.

Tak
<MenuItem Header="Zapisz" Click="Zapisz_Click" />
<Button Content="Zapisz" Click="Zapisz_Click" />

Jedna metoda obsługuje obie drogi, więc logika jest w jednym miejscu.

`InputGestureText` bez prawdziwego skrótu
Tak nie
<MenuItem Header="Zapisz" InputGestureText="Ctrl+S" Click="Zapisz_Click" />

Napis „Ctrl+S” się wyświetla, ale naciśnięcie skrótu nic nie robi.

Tak
<!-- skrót trzeba osobno podpiąć, np. przez KeyBinding w Window.InputBindings -->

InputGestureText tylko opisuje skrót. Działanie to osobna sprawa.

Zbyt głębokie podmenu
Tak nie
Plik → Eksport → Obrazy → Formaty → Rastrowe → PNG

Użytkownik gubi się i nie znajduje opcji.

Tak
Plik → Eksportuj jako…  (dalszy wybór formatu w oknie dialogowym)

Dwa do trzech poziomów to rozsądny limit. Resztę przenieś do okna dialogowego.

7 · Sprawdź się

Menu, pasek czy menu kontekstowe?

Cztery sytuacje z interfejsem edytora.

Ta interakcja wymaga włączonego JavaScriptu.

Podsumowanie

Co warto zapamiętać

  1. Menu składa się z MenuItem, Separator i skrótów. ToolBar to pasek przycisków. ContextMenu pojawia się pod prawym przyciskiem.
  2. _ przed literą w Header tworzy klawisz dostępu (Alt+litera).
  3. InputGestureText tylko wyświetla skrót, jego działanie obsługujesz osobno.
  4. IsCheckable i IsChecked zamieniają pozycję menu w przełącznik.
  5. Wszystkie trzy elementy wskazują te same metody, więc logika jest napisana raz.

Dalej na swoim koncie

Rozgrzewki, quiz i zadania są w biurku ucznia.

Teoria jest otwarta dla wszystkich. Żeby rozwiązywać zadania, zapisywać szkice i widzieć swój postęp, zaloguj się.

Zaloguj się →
Źródła i dalsza nauka