在运行中放置RichTextBox插入符

时间:2014-01-04 19:46:09

标签: c# wpf richtextbox caret flowdocument

我正在尝试将插入符号放在Run中的RichTextBox中,使用户能够继续使用相同的格式进行输入。在此运行之后,还有另一个具有不同格式的运行。

以下是一些代码,向您展示我的意思:

private void Button_Click(object sender, RoutedEventArgs e)
{
    Paragraph p = new Paragraph();

    // Add the new Paragraph to the RichTextBox flowdocument.
    rtb1.Document.Blocks.Add(p);

    // Create the first Run.
    Run r1 = new Run("This is a ");

    // Create the second Run.
    Run r2 = new Run("test");
    r2.TextDecorations = TextDecorations.Underline;

    // Add the new Runs to the Paragraph.
    p.Inlines.Add(r1);
    p.Inlines.Add(r2);

    // Place the caret at the end of the first Run, and give focus to the RichTextBox.
    rtb1.CaretPosition = r1.ContentEnd;
    rtb1.Focus();
}

如果我继续输入,新输入将获得与第二次运行相同的格式。

我也尝试将CaretPosition设置为

new TextRange(r1.ElementEnd, r1.ElementEnd).Start

希望由于它将逻辑方向设置为向后,它可以工作,但无济于事。

有没有办法在第一次运行中设置CaretPosition?

2 个答案:

答案 0 :(得分:1)

我观察了当我选择“a”和“test”之间的空格并开始输入时发生的事情,并看到创建了一个新的Run。我尝试创建一个新的Run并将它放在r1和r2之间,并将CaretPosition设置为newRun.ContentStart,但这不起作用。

我发现如果我...

  1. 创建了一个包含空格的新Run
  2. 将CaretPosition置于新Run的开头(newRun.ContentStart),
  3. 从新的Run
  4. 中删除了空格

    ...我可以使用与新Run相同的格式继续输入。

    我不喜欢这种方法,因为我需要创建一个新的Run而不是只使用它前面的那个。我会留在这里以防万一没有人知道更好的方法,如果没有人能提供更好的解决方案,我会在一周内接受它作为最佳答案。

    以下是完整的代码:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Paragraph p = new Paragraph();
    
        // Add the new Paragraph to the RichTextBox flowdocument.
        rtb1.Document.Blocks.Add(p);
    
        // Create the first Run.
        Run r1 = new Run("This is a ");
    
        // Create the second Run.
        Run r2 = new Run("test");
        r2.TextDecorations = TextDecorations.Underline;
    
        // Add the new Runs to the Paragraph.
        p.Inlines.Add(r1);
        p.Inlines.Add(r2);
    
        // Create a new Run. This will be placed between r1 and r2.
        Run newRun = new Run();
    
        // Copy the formatting from r1 to our new Run.
        CopyInlineFormattingToRun(r1, ref newRun);
    
        // Set the text of the new Run to be a space.
        newRun.Text = " ";
    
        // Place our new Run after r1.
        CreateNewRunAfterExistingRun(r1, newRun);
    
        // Put the caret at the start of newRun.
        rtb1.CaretPosition = newRun.ContentStart;
    
        // Remove the space at the end of newRun.
        newRun.ContentEnd.DeleteTextInRun(-1);
    
        // Give focus to the RichTextBox.
        rtb1.Focus();
    }
    
    /// <summary>
    /// Copies some of the properties in <paramref name="mainInline"/> to <paramref name="receiverRun"/>.
    /// </summary>
    /// <param name="mainInline">The <see cref="Inline"/> containing the desired formatting.</param>
    /// <param name="receiverRun">The <see cref="Run"/> which should receive the formattinh from <paramref name="mainInline"/>.</param>
    internal static void CopyInlineFormattingToRun(Inline mainInline, ref Run receiverRun)
    {
        receiverRun.FontFamily = mainInline.FontFamily;
        receiverRun.FontSize = mainInline.FontSize;
        receiverRun.FontStretch = mainInline.FontStretch;
        receiverRun.FontStyle = mainInline.FontStyle;
        receiverRun.FontWeight = mainInline.FontWeight;
        receiverRun.Foreground = mainInline.Foreground;
        receiverRun.Background = mainInline.Background;
        receiverRun.TextDecorations = mainInline.TextDecorations;
    }
    
    /// <summary>
    /// Places a <see cref="Run"/> after an existing <see cref="Run"/>.
    /// </summary>
    /// <param name="existingRun">The existing <see cref="Run"/> already present in the <see cref="FlowDocument"/>.</param>
    /// <param name="newRun">The new <see cref="Run"/> which will be placed after the <paramref name="existingRun"/> in the <see cref="FlowDocument"/>.</param>
    private void CreateNewRunAfterExistingRun(Run existingRun, Run newRun)
    {
        Paragraph p = (Paragraph)existingRun.Parent;
        p.Inlines.InsertAfter(existingRun, newRun);
    }
    

    如果您想在Run的另一侧执行此操作,则需要更改CreateNewRunAfterExistingRun()以使用InsertAfter而不是ContentStart,您将不得不使用

    // Put the caret at the start of newRun.
    rtb1.CaretPosition = newRun.ContentEnd;
    

    编辑: 您可以订阅 LostFocus LostKeyboardFocus 事件,并根据需要合并两个运行。

答案 1 :(得分:0)

诀窍在于运行有两个“结束”点。

而不是rtb1.CaretPosition = newRun.ContentEnd;(似乎只是在运行结束时“外面”),使用rtb1.CaretPosition = newRun.ElementEnd;(这似乎只是“在其中”)然后是任何活动的风格运行结束将应用于随后键入的所有文本。

通过对已接受答案的调整,无需添加空格,然后DeleteTextInRun(-1)来诱使控件正常工作。