4

I have some code that is designed to alter what is in the clipboard on cut/copy, and it works perfectly for Copy, but I can't get Cut to work.

In the xaml, I've defined a RichTextBox named rtbEditor, in the Loaded event, I set up the CopyingHandler:

DataObject.AddPastingHandler(rtbEditor, new DataObjectPastingEventHandler(OnPaste));
DataObject.AddCopyingHandler(rtbEditor, new DataObjectCopyingEventHandler(OnCopy));

OnCopy is (simplified):

private void OnCopy(object sender, DataObjectCopyingEventArgs e)
{
    // Expand the selection include whole paragraphs only:
    TextPointer newStart = rtbEditor.Selection.Start.Parapgraph.ContentStart;
    TextPointer newEnd = rtbEditor.Selection.End.Paragraph.ContentEnd;
    rtbEditor.Selection.Select(newStart, newEnd);

    // copy the selected text
    TextRange range = new TextRange(rtbEditor.Selection.Start, rtbEditor.Selection.End);
    Clipboard.SetText(range.Text);

    e.CancelCommand();
}

This works wonders for Copy, but I'm running into problems making Cut work.

I tried simply expanding the selection with rtbEditor.Selection.Select() and that was it, but the DataObject containing the copied data has been filled already by the time the CopyingHandler has been called, so changing the selection doesn't change what will be placed in the clipboard. (I'm still doing it for the visual feedback to the user that their selection has been expanded)

If I remove e.CancelCommand(), then the cut will correctly delete the text, but only the text that was originally selected and not the expanded selection, and the clipboard will contain only the text that was originally selected, and not the expanded selection either. I'm assuming because since the command isn't cancelled, my Clipboard.SetText() is immediately overwritten by the contents of the DataObject when the cut command finishes.

I also can't find anything in sender or DataObjectCopyingEventArgs that distinguishes whether this event is a Cut event or a Copy event so I can have my code delete the text if it's a Cut.

Is there a way to distinguish here between Cut and Copy that I'm not seeing? Or is there some event I can hook in to that is earlier in the process? MSDN says the CopyingHandler happens "when a copy operation has finished converting the selected content...". But I can't find any event that occurs before the copy operation starts. Or do I need to approach this in a completely different manner?

I found a similar question to this in the comments of How to override copy and paste in richtextbox but it had no answers there

CBauer
  • 51
  • 6

2 Answers2

1

Here's how I ended up solving the problem. I found this page describing intercepting commands before they execute. ( Also mentioned in the answer of Make WPF textbox as cut, copy and paste restricted )

in the XAML I exited the RichTextBox to add an event for CommandManager.PreviewExecuted:

<RichTextBox Name="rtbEditor" ... CommandManager.PreviewExecuted="rtbEditor_PreviewExecuted" >

rtbEditor_PreviewExecuted gets called whenever ANY command is about to execute on rtbEditor. I intercept the Cut and Copy events and put my logic there to expand the selection to only paragraphs, and added a bool flag to my MainWindow class to flag whether the incoming event was a Cut or a Copy.

private void rtbEditor_PreviewExecuted(object sender, ExecutedRoutedEventArgs e)
{
    if (e.Command == ApplicationCommands.Copy)
    {
        ExpandSelectionForCopy();
        mHandlingCutAction = false;
    }
    else if( e.Command == ApplicationCommands.Cut )
    {
        ExpandSelectionForCopy();
        mHandlingCutAction = true;
    }
}

This allowed me to change the selection in the RichTextBox before the built in Cut/Copy logic got to it, so by the time the CopyingHandler is called, the selection has been expanded and the DataObject is filled out properly.

Extra logic for special handling can still be added to the CopyingHandler, using the mHandlingCutAction flag to tell if it's a cut or a copy action.

CBauer
  • 51
  • 6
0

You can use CommandBindings.

this.RichTextBox.CommandBindings.Add(new CommandBinding(ApplicationCommands.Cut, this.RichTextBoxCutEvent));
this.RichTextBox.CommandBindings.Add(new CommandBinding(ApplicationCommands.Cut, this.RichTextBoxCopyEvent));

private void RichTextBoxCutEvent(object sender, ExecutedRoutedEventArgs e)
{
    // The cut actions
}

private void RichTextBoxCopyEvent(object sender, ExecutedRoutedEventArgs e)
{
    // The copy actions
}
marsh-wiggle
  • 2,508
  • 3
  • 35
  • 52