Jak użyć niestandardowego menu kontekstowego za pomocą TextBox

W tym przykładzie pokazano, jak zdefiniować i zaimplementować proste niestandardowe menu kontekstowe dla elementu TextBox.

Definiowanie niestandardowego menu kontekstowego

Poniższy przykład extensible Application Markup Language (XAML) definiuje kontrolkę TextBox zawierającą niestandardowe menu kontekstowe.

Menu kontekstowe jest definiowane ContextMenu przy użyciu elementu. Menu kontekstowe składa się z serii MenuItem elementów i Separator elementów. Każdy MenuItem element definiuje polecenie w menu kontekstowym; Header atrybut definiuje tekst wyświetlany dla polecenia menu, a Click atrybut określa metodę obsługi dla każdego elementu menu. Element Separator po prostu powoduje renderowanie linii oddzielającej między poprzednimi i kolejnymi elementami menu.

<TextBox
  Name="cxmTextBox" 
  Grid.Row="1"
  AcceptsReturn="True"
  AcceptsTab="True"
  VerticalScrollBarVisibility="Visible"
  TextWrapping="Wrap"
>
  <TextBox.ContextMenu>
    <ContextMenu 
      Name="cxm"
      Opened="CxmOpened"
    >
      <MenuItem 
        Header="Cut"
        Name="cxmItemCut" 
        Click="ClickCut" 
      />
      <MenuItem 
        Header="Copy" 
        Name="cxmItemCopy"
        Click="ClickCopy" 
      />
      <MenuItem 
        Header="Paste"
        Name="cxmItemPaste"
        Click="ClickPaste" 
      />
      <Separator/>
      <MenuItem 
        Header="Select All"
        Name="cxmItemSelectAll"
        Click="ClickSelectAll" 
      />
      <MenuItem 
        Header="Select Current Line"
        Name="cxmItemSelectLine"
        Click="ClickSelectLine" 
      />
      <Separator/>
      <MenuItem 
        Header="Undo Last Action"
        Name="cxmItemUndo"
        Click="ClickUndo" 
      />
      <MenuItem 
        Header="Redo Last Action"
        Name="cxmItemRedo"
        Click="ClickRedo" 
      />
      <Separator/>
      <MenuItem 
        Header="Clear All Text"
        Name="cxmItemClear"
        Click="ClickClear" 
      />
    </ContextMenu>
  </TextBox.ContextMenu>
  This TextBox uses a simple custom context menu.  The context menu can be disabled by checking
  the CheckBox above, which simply sets the TextBox.ContextMenu property to null.
</TextBox>

Implementowanie niestandardowego menu kontekstowego

Poniższy przykład przedstawia kod implementacji poprzedniej definicji menu kontekstowego, a także kod, który włącza i wyłącza menu kontekstowe. Zdarzenie Opened jest używane do dynamicznego włączania lub wyłączania niektórych poleceń w zależności od bieżącego TextBoxstanu .

Aby przywrócić domyślne menu kontekstowe, użyj ClearValue metody , aby wyczyścić wartość ContextMenu właściwości. Aby całkowicie wyłączyć menu kontekstowe, ustaw ContextMenu właściwość na odwołanie o wartości null (Nothing w Visual Basic).

private void MenuChange(Object sender, RoutedEventArgs ags)
{
    RadioButton rb = sender as RadioButton;
    if (rb == null || cxm == null) return;

    switch (rb.Name)
    {
        case "rbCustom":
            cxmTextBox.ContextMenu = cxm;
            break;
        case "rbDefault":
            // Clearing the value of the ContextMenu property
            // restores the default TextBox context menu.
            cxmTextBox.ClearValue(ContextMenuProperty);
            break;
        case "rbDisabled":
            // Setting the ContextMenu propety to
            // null disables the context menu.
            cxmTextBox.ContextMenu = null;
            break;
        default:
            break;
    }
}

void ClickPaste(Object sender, RoutedEventArgs args)     { cxmTextBox.Paste(); }
void ClickCopy(Object sender, RoutedEventArgs args)      { cxmTextBox.Copy(); }
void ClickCut(Object sender, RoutedEventArgs args)       { cxmTextBox.Cut(); }
void ClickSelectAll(Object sender, RoutedEventArgs args) { cxmTextBox.SelectAll(); }
void ClickClear(Object sender, RoutedEventArgs args)     { cxmTextBox.Clear(); }
void ClickUndo(Object sender, RoutedEventArgs args)      { cxmTextBox.Undo(); }
void ClickRedo(Object sender, RoutedEventArgs args)      { cxmTextBox.Redo(); }

void ClickSelectLine(Object sender, RoutedEventArgs args)
{
    int lineIndex = cxmTextBox.GetLineIndexFromCharacterIndex(cxmTextBox.CaretIndex);
    int lineStartingCharIndex = cxmTextBox.GetCharacterIndexFromLineIndex(lineIndex);
    int lineLength = cxmTextBox.GetLineLength(lineIndex);
    cxmTextBox.Select(lineStartingCharIndex, lineLength);
}

void CxmOpened(Object sender, RoutedEventArgs args)
{
    // Only allow copy/cut if something is selected to copy/cut.
    if (cxmTextBox.SelectedText == "")
        cxmItemCopy.IsEnabled = cxmItemCut.IsEnabled = false;
    else
        cxmItemCopy.IsEnabled = cxmItemCut.IsEnabled = true;

    // Only allow paste if there is text on the clipboard to paste.
    if (Clipboard.ContainsText())
        cxmItemPaste.IsEnabled = true;
    else
        cxmItemPaste.IsEnabled = false;
}
Private Sub MenuChange(ByVal sender As Object, ByVal args As RoutedEventArgs)
    Dim rb As RadioButton = CType(sender, RadioButton)
    If myGrid.Children.Contains(cxmTextBox) Then
        Select Case rb.Name
            Case "rbCustom"
                cxmTextBox.ContextMenu = cxm
            Case "rbDefault"
                'Clearing the value of the ContextMenu property
                'restores the default TextBox context menu.
                cxmTextBox.ClearValue(ContextMenuProperty)
            Case "rbDisabled"
                'Setting the ContextMenu propety to 
                'null disables the context menu.
                cxmTextBox.ContextMenu = Nothing
        End Select
    Else : Return
    End If
End Sub

Private Sub ClickPaste(ByVal sender As Object, ByVal args As RoutedEventArgs)
    cxmTextBox.Paste()
End Sub
Private Sub ClickCopy(ByVal sender As Object, ByVal args As RoutedEventArgs)
    cxmTextBox.Copy()
End Sub
Private Sub ClickCut(ByVal sender As Object, ByVal args As RoutedEventArgs)
    cxmTextBox.Cut()
End Sub
Private Sub ClickSelectAll(ByVal sender As Object, ByVal args As RoutedEventArgs)
    cxmTextBox.SelectAll()
End Sub
Private Sub ClickClear(ByVal sender As Object, ByVal args As RoutedEventArgs)
    cxmTextBox.Clear()
End Sub
Private Sub ClickUndo(ByVal sender As Object, ByVal args As RoutedEventArgs)
    cxmTextBox.Undo()
End Sub
Private Sub ClickRedo(ByVal sender As Object, ByVal args As RoutedEventArgs)
    cxmTextBox.Redo()
End Sub
Private Sub ClickSelectLine(ByVal sender As Object, ByVal args As RoutedEventArgs)
    Dim lineIndex As Integer = cxmTextBox.GetLineIndexFromCharacterIndex(cxmTextBox.CaretIndex)
    Dim lineStartingCharIndex As Integer = cxmTextBox.GetCharacterIndexFromLineIndex(lineIndex)
    Dim lineLength As Integer = cxmTextBox.GetLineLength(lineIndex)
    cxmTextBox.Select(lineStartingCharIndex, lineLength)
End Sub
Private Sub CxmOpened(ByVal sender As Object, ByVal args As RoutedEventArgs)
    'Only allow copy/cut if something is selected to copy/cut.
    If cxmTextBox.SelectedText = "" Then
        cxmItemCopy.IsEnabled = cxmItemCut.IsEnabled = False
    Else
        cxmItemCopy.IsEnabled = cxmItemCut.IsEnabled = True
        'Only allow paste if there is text on the clipboard to paste.
        If Clipboard.ContainsText() Then
            cxmItemPaste.IsEnabled = True
        Else
            cxmItemPaste.IsEnabled = False
        End If
    End If
End Sub

Zobacz też