4
internal string Select(RichTextBox rtb, int index, int length)
    {
        TextRange textRange = new TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd);

        if (textRange.Text.Length >= (index + length))
        {
            TextPointer start = textRange.Start.GetPositionAtOffset(index, LogicalDirection.Forward);
            TextPointer end = textRange.Start.GetPositionAtOffset(index + length, LogicalDirection.Backward);
            rtb.Selection.Select(start, end); 
            rtb.Selection.ApplyPropertyValue(TextElement.BackgroundProperty, new SolidColorBrush(Colors.LightBlue)); 
        }
        return rtb.Selection.Text;
    } 

選択したテキストの背景色を変更するために ApplyPropertyValue が呼び出されると、最初はうまく機能しますが、2 回目に呼び出されたときに選択したテキスト セグメントの背景色が適切に調整されません。これは、関数が呼び出された後にドキュメントのオフセットが何らかの形で台無しになっていることに関係していると思われます。

これを修正する良い方法は何ですか?

4

3 に答える 3

7

これを試してみてください(あなたのものよりも少し複雑なロジックが必要です)、そうでなければはい:オフセットに問題があります!

private static TextPointer GetTextPointAt(TextPointer from, int pos)
{
        TextPointer ret = from;
        int i = 0;

        while ((i < pos) && (ret != null))
        {
            if ((ret.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.Text) || (ret.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.None))
                i++;

            if (ret.GetPositionAtOffset(1, LogicalDirection.Forward) == null)
                return ret;

            ret = ret.GetPositionAtOffset(1, LogicalDirection.Forward);
        }

        return ret;
}

internal string Select(RichTextBox rtb, int offset, int length, Color color)
{
        // Get text selection:
        TextSelection textRange = rtb.Selection;

        // Get text starting point:
        TextPointer start = rtb.Document.ContentStart;

        // Get begin and end requested:
        TextPointer startPos = GetTextPointAt(start, offset);
        TextPointer endPos = GetTextPointAt(start, offset + length);

        // New selection of text:
        textRange.Select(startPos, endPos);

        // Apply property to the selection:
        textRange.ApplyPropertyValue(TextElement.BackgroundProperty, new SolidColorBrush(color));

        // Return selection text:
        return rtb.Selection.Text;
}

そして、次のように使用します (最初の文字から RED の 5 番目の文字までを選択しています)。

this.Select(this.myRichTextBox, 0, 5, Colors.Red);
于 2012-08-27T12:11:48.273 に答える
1

まず第一に、MAXE による素晴らしい回答です。これは、私が抱えていた根本的な問題を明確に示したからです。WPF のフロー ドキュメント コントロールは生のテキストではなく、マークアップを処理していることを覚えておく必要があります。したがって、根本的な問題は、実際に含まれている要素内のテキストを処理するまで、マークアップをスキップすることです。

このソリューションの問題は、非常に遅いことです。例として、約 150 個のテキストを選択するアプリケーションは、このメソッドを使用して実行するのに約 20 秒かかり、そのうちの約 20 ミリ秒を除いてテキストの選択に費やされました!

すべてのシナリオで機能するこの問題に対する一般的な解決策はありませんが、何を達成しようとしているのかを慎重に検討し、それに応じて最適化することには価値があります。一般的なシナリオは、単一のラン (段落など) を作成し、そこにテキストのブロックを配置してから、その単一の要素内のテキストを選択/強調表示することです。このシナリオでは、「要素」が 1 つしかないことがわかっているため、次の操作を実行すると、上記と同じ結果が得られます。

   internal static TextPointer GetOffsetTextPointer(this TextPointer start, int offset)
    {
        return start.GetInsertionPosition(LogicalDirection.Forward).GetPositionAtOffset(offset);
    }

参考までに、GetInsertionPositionメソッドは開始要素のマークアップをスキップして、テキストが実際に始まるポイントまでスキップし、GetPositionAtOffsetメソッドは 1 回の呼び出しで実際のポインターを取得します。比較のために、上記の例の実行にかかる時間は 2 秒未満になりました。

于 2013-03-10T13:42:09.420 に答える