首页 > 解决方案 > 从 CaretPosition 在 RichTextBox 中写入样式文本

问题描述

我有一个RichTextBox带有一些用于文本样式的标准按钮的 WPF。因为它们都应该以相同的方式工作,所以从现在开始,我将使用使文本变为粗体的示例。所以,我的目标是,用户可以单击粗体按钮,然后,他写的文本将从插入符号所在的位置变为粗体。必须在流文档的内联中设置样式(因为我必须将包括样式在内的整个文本作为 xaml 字符串传输到另一个对象)。在这一点上,我将发布我的代码。请注意,这是我创建的一个简单的测试项目,用于测试解决这个特定问题的方法。

首先是xaml:

<Window x:Class="rtbTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:rtbTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="180"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <DockPanel
            Grid.Row="0"
            LastChildFill="False">
            <StackPanel
            DockPanel.Dock="Left"    
            Orientation="Horizontal"
            Background="Gray">
                <TextBlock
                Foreground="#000000"
                FontWeight="Bold"
                VerticalAlignment="Center"
                Text="Font" 
             />
                <ComboBox 
                x:Name="fonts" 
                Margin="10,2,20,2"
                >
                </ComboBox>
                <TextBlock
                Foreground="#000000"
                FontWeight="Bold"
                VerticalAlignment="Center"
                Text="Size" 
             />
                <ComboBox 
                x:Name="fontsize" 
                Margin="10,2,20,2"
                >
                </ComboBox>
                <ToggleButton
                x:Name="bold"
                Content="B"
                Margin="0,2,5,2"
                Width="30">
                </ToggleButton>
                <ToggleButton
                x:Name="italic"
                Content="I"
                Margin="0,2,5,2"
                Width="30">
                </ToggleButton>
            </StackPanel>
        </DockPanel>

        <RichTextBox
            Name="textbox"
            Grid.Row="1" Grid.ColumnSpan="2" >
        </RichTextBox>

        <ScrollViewer
                Grid.Row="2"
                Grid.ColumnSpan="2"
                Margin="0,10,0,0"
                VerticalScrollBarVisibility="Auto">
            <StackPanel
                    Name="entrys"
                    Background="Black"
                    >
            </StackPanel>
        </ScrollViewer>
    </Grid>
</Window>

然后是代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using function = System.String;
namespace rtbTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.InitializeTextStyling();
        }

        private void InitializeTextStyling()
        {
            this.AddFonts();
            this.fonts.SelectedIndex = 1;
            this.textbox.IsInactiveSelectionHighlightEnabled = true;

            this.fonts.SelectionChanged += (s, a) =>
            {
                if (this.fonts.SelectedIndex != 0)
                {
                    if (this.textbox.Selection.IsEmpty)
                    {
                        this.textbox.Document.FontFamily = ((ComboBoxItem)this.fonts.SelectedItem).Content as FontFamily;
                    }
                    else
                    {
                        this.textbox.Selection.ApplyPropertyValue(TextBlock.FontFamilyProperty, ((ComboBoxItem)this.fonts.SelectedItem).Content as FontFamily);
                    }
                }
            };


            for (double i = 10; i < 80; i = i + 1)
            {
                this.fontsize.Items.Add(i);
            }
            this.fontsize.SelectionChanged += (s, a) =>
            {
                if (this.textbox.Selection.IsEmpty)
                {
                    this.textbox.Document.FontSize = double.Parse(this.fontsize.SelectedItem.ToString());
                }
                else
                {
                    this.textbox.Selection.ApplyPropertyValue(TextBlock.FontSizeProperty, double.Parse(this.fontsize.SelectedItem.ToString()));
                }
            };
            this.fontsize.SelectedItem = 40.0;

            this.italic.Checked += (s, a) =>
            {
                if (this.textbox.Selection.IsEmpty)
                {
                    this.textbox.Document.FontStyle = FontStyles.Italic;
                }
                else
                {
                    this.textbox.Selection.ApplyPropertyValue(TextBlock.FontStyleProperty, FontStyles.Italic);
                }
            };

            this.italic.Unchecked += (s, a) =>
            {
                if (this.textbox.Selection.IsEmpty)
                {
                    this.textbox.Document.FontStyle = FontStyles.Normal;
                }
                else
                {
                    this.textbox.Selection.ApplyPropertyValue(TextBlock.FontStyleProperty, FontStyles.Normal);
                }
            };

            this.bold.Checked += (s, a) =>
            {
                this.textbox.Focus();
                if (this.textbox.Selection.IsEmpty)
                {
                    TextPointer tp = this.textbox.CaretPosition;
                    Run r = new Run("test", tp);
                    r.FontWeight = FontWeights.Bold;
                    this.textbox.CaretPosition = r.ElementStart;
                    r.Text = "";
                    string fds = XamlWriter.Save(this.textbox.Document);
                }
                else
                {
                    this.textbox.Selection.ApplyPropertyValue(TextBlock.FontWeightProperty, FontWeights.Heavy);
                }
            };

            this.bold.Unchecked += (s, a) =>
            {
                if (this.textbox.Selection.IsEmpty)
                {
                    this.textbox.Document.FontWeight = FontWeights.Normal;
                }
                else
                {
                    this.textbox.Selection.ApplyPropertyValue(TextBlock.FontWeightProperty, FontWeights.Normal);
                }
            };

            FlowDocument fd = new FlowDocument();
            fd.FontSize = double.Parse(this.fontsize.SelectedItem.ToString());
            fd.FontFamily = ((ComboBoxItem)this.fonts.SelectedItem).Content as FontFamily;
            fd.FontWeight = FontWeights.Normal;
            this.textbox.Document = fd;

        }

        private function GetStringFromStream(Stream stream)
        {
            using (StreamReader r = new StreamReader(stream))
            {
                return r.ReadToEnd();
            }
        }


        private void AddFonts()
        {
            //foreach (System.Drawing.FontFamily f in System.Drawing.FontFamily.Families)
            //{
            //    ComboBoxItem item = new ComboBoxItem();
            //    item.Content = new FontFamily(f.GetName(0));
            //    item.FontFamily = (FontFamily)item.Content;
            //    this.fonts.Items.Add(item);
            //}

            ComboBoxItem item = new ComboBoxItem();
            item.Content = new FontFamily("Arial");
            item.FontFamily = (FontFamily)item.Content;
            this.fonts.Items.Add(item);

            item = new ComboBoxItem();
            item.Content = new FontFamily("Corbel");
            item.FontFamily = (FontFamily)item.Content;
            this.fonts.Items.Add(item);

            item = new ComboBoxItem();
            item.Content = new FontFamily("Gabriola");
            item.FontFamily = (FontFamily)item.Content;
            this.fonts.Items.Add(item);

            item = new ComboBoxItem();
            item.Content = new FontFamily("MingLiU - ExtB");
            item.FontFamily = (FontFamily)item.Content;
            this.fonts.Items.Add(item);

            item = new ComboBoxItem();
            item.Content = new FontFamily("MV Boli");
            item.FontFamily = (FontFamily)item.Content;
            this.fonts.Items.Add(item);

            item = new ComboBoxItem();
            item.Content = new FontFamily("Noto Naskh Arabic UI");
            item.FontFamily = (FontFamily)item.Content;
            this.fonts.Items.Add(item);
        }
    }
}

这段代码应该足以立即进行测试。

现在,我的问题出在这部分:

this.bold.Checked += (s, a) =>
{
    this.textbox.Focus();
    if (this.textbox.Selection.IsEmpty)
    {
        TextPointer tp = this.textbox.CaretPosition;
        Run r = new Run("test", tp);
        r.FontWeight = FontWeights.Bold;
        this.textbox.CaretPosition = r.ElementStart;
        r.Text = "";
        string fds = XamlWriter.Save(this.textbox.Document);
    }
    else
    {
        this.textbox.Selection.ApplyPropertyValue(TextBlock.FontWeightProperty, FontWeights.Heavy);
    }
};

我真正需要做的是插入Run没有文字的内容。但是如果我这样做,当我使用带有初始文本(如“test”)的构造函数时,以这种方式插入一个 Run<Run FontWeight="bold" />而不是<Run FontWeight="bold"></Run>. 我可以获得第二个(我需要的),然后我也可以将插入符号位置设置为新创建的运行。但后来我的 RTB 中有文本,这是我不想要的。我想在构造函数中设置文本,然后将文本设置为空,但如果我这样做,插入的内容Run会再次恢复到第一个版本,我无法在Run. 有没有办法实现这一点:run在插入符号位置插入一个新的空白,文本样式为粗体,插入符号位置设置在这个新的运行中?

请注意,fds仅设置了字符串,因此我可以在调试时将流文档视为 XAML 字符串。

标签: c#wpfrichtextboxinlineflowdocument

解决方案


推荐阅读