Question

Due to an issue with large images in C1RichTextBox for Silverlight (5.0.20132.340), I want to implement the copy/cut/paste operations in my custom control. I am using the events C1RichTextBox.ClipboardCopying and C1RichTextBox.ClipboardPasting to do this. These are the only events (no ClipboardCutting event) and I don't see any overrideable methods to solve this differently.

Now when I do a CUT operation in the rich text box, the event C1RichTextBox.ClipboardCopying is fired too but I cannot decide whether it is Copy or Cut. There is a private member C1RichTextBox._isCutOperation which is used internally.

Any ideas how to decide whether Copy or Cut is being done?

Was it helpful?

Solution

I also asked this question in the ComponentOne support forum and here's what they came up with:

I would suggest you rather listen to KeyDown event for Ctrl+X and call C1RichTextBox.ClipBoardCut method. This way you would be able to handle the cur operation on C1RichTextBox.

Which lead me to the conclusion that you cannot use the event ClipboardCopying to implement custom Copy/Cut operation.

(Edit: See this question how to implement custom Copy/Cut/Paste)

After a few hours of tinkering I found the following solution (just in case someone else is going crazy over this):

public class C1RichTextBoxExt : C1RichTextBox
{
    public C1RichTextBoxExt( )
    {
        ClipboardMode = ClipboardMode.RichText;

        // Workaround for Copy/Paste issue in C1RichTextBox (5.0.20132.340) -> large images are not copied.
        ClipboardCopying += new EventHandler<ClipboardEventArgs>(RichTextBox_ClipboardCopying);
        ClipboardPasting += new EventHandler<ClipboardEventArgs>(RichTextBox_ClipboardPasting);
    }

    void RichTextBox_ClipboardCopying(object sender, ClipboardEventArgs e)
    {
        // store info in static fields since Silverlight clipboard cannot store html and text at the same time.
        _clipboardHtml = Selection.Html;
        _clipboardText = Selection.Text;

        // Another Workaround: cannot determine if Copy or Cut is going on ...
        // -> call the ClipboardCopy() method and let the C1RichTextBox do the cut/copy. Calling this method will
        //    however trigger the ClipboardCopying event again, so we most remove this method as event handler 
        //    temporarily.
        ClipboardCopying -= RichTextBox_ClipboardCopying;
        ClipboardCopy();
        ClipboardCopying += RichTextBox_ClipboardCopying;

        e.Handled = true; // operation is done, nothing more to do.
    }

    void RichTextBox_ClipboardPasting(object sender, ClipboardEventArgs e)
    {
        string current = Clipboard.GetText();
        // texts will not match exactly since C1 uses a different approach to copy text to the clipboard than
        // just using Selection.Text...

        if (TextsEqual(current, _clipboardText))
        {
            // text is the same -> assumption that html is still valid. Paste _clipboardHtml
            using (new DocumentHistoryGroup(DocumentHistory)) // enables undo/redo
            {
                // code from C1 library to paste html correctly ///////////////////
                C1Document c1Document = HtmlFilter.ConvertToDocument(_clipboardHtml);

                C1TextPointer c1TextPointer = c1Document.ContentStart;
                C1TextRange selection = Selection;
                C1TextPointer c1TextPointer2 = selection.Delete(!Selection.IsEmpty, false);

                List<Type> list = Enumerable.ToList<Type>(Enumerable.Select<C1TextElement, Type>(c1TextPointer2.Element.GetParents(), (C1TextElement elem) => elem.GetType()));
                list.Add(c1TextPointer2.Element.GetType());
                while (c1TextPointer.Symbol is StartTag && (c1TextPointer.Symbol as Tag).Element is C1Block && !((c1TextPointer.Symbol as Tag).Element is C1TableRowGroup) && list.Contains((c1TextPointer.Symbol as Tag).Element.GetType()))
                {
                    c1TextPointer = c1TextPointer.GetPositionAtOffset(1);
                }
                C1TextPointer c1TextPointer3 = c1Document.ContentEnd;
                while (c1TextPointer3.PreviousSymbol is EndTag)
                {
                    c1TextPointer3 = c1TextPointer3.GetPositionAtOffset(-1);
                }
                c1Document.FragmentRange = new C1TextRange(c1TextPointer, c1TextPointer3);
                selection.Fragment = c1Document;
                Selection = new C1TextRange(selection.End);
                Focus();
                // end of C1 library code ////////////////////////
            }
            e.Handled = true; // paste is done
        }
        else
        {
            // text is different -> something newer got copied from another control or application
            // -> let C1RichTextBox paste
        }
    }

    private bool TextsEqual(string t1, string t2)
    {
        if (string.IsNullOrEmpty(t1) || string.IsNullOrEmpty(t2))
        {
            return false;
        }

        IEnumerable<char> chars1 = t1.Where(c => Char.IsLetterOrDigit(c));
        t1 = new string(chars1.ToArray());

        IEnumerable<char> chars2 = t2.Where(c => Char.IsLetterOrDigit(c));
        t2 = new string(chars2.ToArray());

        return t1 == t2;
    }

    private static string _clipboardText;
    private static string _clipboardHtml;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top