Реализуйте операцию вырезания из буфера обмена с помощью C1RichTextBox

Из-за проблемы с большими изображениями в C1RichTextBox для Silverlight (5.0.20132.340) я хочу реализовать операции копирования / вырезания / вставки в моем настраиваемом элементе управления. Для этого я использую события C1RichTextBox.ClipboardCopying и C1RichTextBox.ClipboardPasting. Это единственные события (без события ClipboardCutting), и я не вижу никаких переопределяемых методов, позволяющих решить эту проблему по-другому.

Теперь, когда я выполняю операцию CUT в поле форматированного текста, событие C1RichTextBox.ClipboardCopying также запускается, но я не могу решить, является ли оно копией или вырезанием. Есть закрытый член C1RichTextBox._isCutOperation, который используется внутри компании.

Есть идеи, как решить, выполняется копирование или вырезание?


person helb    schedule 08.11.2013    source источник
comment
См. Также более общий вопрос с более приятным ответом: stackoverflow.com/questions/31734350/   -  person helb    schedule 31.07.2015


Ответы (1)


Я также задал этот вопрос на форуме поддержки ComponentOne, и вот что они придумали:

Я бы посоветовал вам прослушать событие KeyDown для Ctrl + X и вызвать метод C1RichTextBox.ClipBoardCut. Таким образом, вы сможете обрабатывать текущую операцию над C1RichTextBox.

Это привело меня к выводу, что вы не можете использовать событие ClipboardCopying для реализации пользовательской операции копирования / вырезания.

(Изменить: см. этот вопрос, как реализовать пользовательское копирование / вырезание / вставка)

После нескольких часов работы я нашел следующее решение (на случай, если кто-то еще сойдет с ума по этому поводу):

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;
}
person helb    schedule 15.11.2013
comment
Мне было интересно, есть ли у вас какие-либо предложения по этому сообщению, также относящемуся к ComponentOne? - person nam; 17.03.2019