Написать стилизованный текст в RichTextBox из CaretPosition - PullRequest
0 голосов
/ 04 ноября 2019

У меня есть WPF RichTextBox с некоторыми стандартными кнопками для оформления текста. Поскольку все они должны работать одинаково, я собираюсь использовать пример выделения текста жирным шрифтом. Итак, моя цель состоит в том, чтобы пользователь мог нажать кнопку жирного шрифта, а затем текст, который он пишет, будет выделен жирным шрифтом, где бы ни находился курсор на этом этапе. Стиль должен быть установлен во встроенных документах потока (потому что мне нужно перенести весь текст, включая стиль, в другой объект в виде строки 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 без текста. Но если я сделаю это, Run будет вставлен таким образом <Run FontWeight="bold" /> вместо <Run FontWeight="bold"></Run>. Я смогу получить второй (тот, который мне нужен), когда я использую конструктор с исходным текстом типа «test», а затем я такжеможет установить позицию каретки для вновь созданного прогона. Но тогда у меня есть текст в моем RTB, который я не хочу. Я думал об установке текста в конструкторе и позже установил текст пустым, но если я это сделаю, вставленный Run снова вернется к первой версии, и я не смогу установить позицию каретки внутри Run. Есть ли способ добиться этого: вставить новую пустую run в позицию каретки с текстом в стиле полужирный и позицию каретки, установленную в этом новом прогоне?

Обратите внимание, что fds строка была установлена ​​только для того, чтобы я мог видеть документ потока как строку XAML во время отладки.

...