WPF,RichTextBox,SelectionBrush,而不是SelectionBackColor

时间:2017-08-29 00:40:53

标签: wpf richtextbox

在WPF应用程序RichTextBox中,我正在尝试找到一种方法来为框内的各种单词提供背景颜色。在RichTextBox的System.Windows.Forms版本中,有一种非常简单的方法:

richTextBox1.SelectionBackColor = color;
richTextBox1.AppendText(word);

但是,RichTextBox的System.Windows.Controls版本只有SelectionBrush,并且这种方法不起作用。

RichTextBox中不同单词的背景颜色是否可能?

1 个答案:

答案 0 :(得分:3)

您可以使用FlowDocument

中的RichTextBox
<RichTextBox>
    <RichTextBox.Document>
        <FlowDocument>
            <Paragraph>
                <Run Background="Red">Hello World</Run>
                <LineBreak/>
                <Run Background="Green">This is a colored</Run>
                <Run>text.</Run>
            </Paragraph>
        </FlowDocument>
    </RichTextBox.Document>
</RichTextBox>

关于您的评论进行修改:显示两种不同方法的(几乎)完整示例。

无论您最终如何在UI中显示文本,您都应该拥有某种逻辑,以便为突出显示的文本创建合适的数据模型。以下示例使用TextFragment的集合,其中每个片段可选地标记为突出显示。

public class TextFragment
{
    public TextFragment(string text, bool isHighlighted)
    {
        this.Text = text;
        this.IsHighlighted = isHighlighted;
    }
    public string Text { get; private set; }

    public bool IsHighlighted { get; private set; }
}

此外,对于示例,我使用类TextEntry来管理原始文本,搜索文本和生成的文本片段。注意我继承自BaseViewModel类,它为INotifyPropertyChanged相关事物实现了一些辅助函数。辅助函数bool SetProperty<T>(ref T store, T value, [CallerMemberName]string propertyName = null)将检查值和存储是否相等,可能使用值更新存储并引发属性更改通知。返回值表示该值是否真的不同/已更改。

public class TextEntry : BaseViewModel
{
    public TextEntry()
    {
        TextParts = new ObservableCollection<TextFragment>();
    }

    private void UpdateTextParts()
    {
        TextParts.Clear();

        if (string.IsNullOrEmpty(SearchText))
        {
            TextParts.Add(new TextFragment(OriginalText, false));
            return;
        }

        int startAt = 0;
        do
        {
            int next = OriginalText.IndexOf(SearchText, startAt, StringComparison.CurrentCultureIgnoreCase);
            if (next == -1)
            {
                TextParts.Add(new TextFragment(OriginalText.Substring(startAt), false));
                return;
            }
            else
            {
                if (next != startAt)
                {
                    TextParts.Add(new TextFragment(OriginalText.Substring(startAt, next - startAt), false));
                }
                // add highlighted part
                TextParts.Add(new TextFragment(OriginalText.Substring(next, SearchText.Length), true));
                startAt = next + SearchText.Length;
            }
        } while (startAt < OriginalText.Length);
    }


    private string _OriginalText;
    public string OriginalText
    {
        get { return _OriginalText; }
        set
        {
            if (SetProperty(ref _OriginalText, value))
            {
                UpdateTextParts();
            }
        }
    }


    private string _SearchText;
    public string SearchText
    {
        get { return _SearchText; }
        set
        {
            if (SetProperty(ref _SearchText, value))
            {
                UpdateTextParts();
            }
        }
    }

    public ObservableCollection<TextFragment> TextParts { get; private set; }
}

您可以通过在水平StackPanel中附加具有不同文本设置的多个文本块来在UI中创建多部分文本。这样,文本部分可以由ItemsControl管理。或者,您可以使用RichTextBox及其Document属性,但这需要在后面的代码中进行更多处理。

主窗口中的一些初始化代码和更新RichTextBox示例文档的方法:

public MainWindow()
{
    InitializeComponent();
    var vm = new TextEntry();
    grid1.DataContext = vm;
    // this trigger works, but don't ask about efficiency for a bigger application
    vm.TextParts.CollectionChanged += TextParts_CollectionChanged;
}

void TextParts_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    ObservableCollection<TextFragment> data = sender as ObservableCollection<TextFragment>;
    var doc = richTextBox1.Document;
    var paragraph = new Paragraph();
    paragraph.Inlines.AddRange(data.Select(x =>
    {
        var run = new Run(x.Text);
        if (x.IsHighlighted)
        {
            run.Background = Brushes.LightCoral;
        }
        return run;
    }));
    doc.Blocks.Clear();
    doc.Blocks.Add(paragraph);
}

窗口的XAML内容:

<Grid x:Name="grid1">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0" Grid.Column="0" Text="Original Text: " Margin="3"/>
    <TextBlock Grid.Row="1" Grid.Column="0" Text="Searched Word: " Margin="3"/>
    <TextBlock Grid.Row="2" Grid.Column="0" Text="Highlighted Text: " Margin="3"/>
    <TextBlock Grid.Row="3" Grid.Column="0" Text="Highlighted Text2: " Margin="3"/>
    <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding OriginalText, UpdateSourceTrigger=PropertyChanged}" Margin="3"/>
    <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding SearchText,UpdateSourceTrigger=PropertyChanged}" Margin="3"/>
    <ItemsControl Grid.Row="2" Grid.Column="1" ItemsSource="{Binding TextParts}" Margin="3" IsTabStop="False">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" VerticalAlignment="Top"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Text}">
                    <TextBlock.Style>
                        <Style TargetType="TextBlock">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding IsHighlighted}" Value="True">
                                    <Setter Property="Background" Value="LightCoral"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </TextBlock.Style>
                </TextBlock>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    <RichTextBox Grid.Row="3" Grid.Column="1" x:Name="richTextBox1" Margin="3" VerticalAlignment="Top" IsReadOnly="True"/>
</Grid>

预期计划:

两行文字输入。一个用于原始文本,一个用于搜索文本。

第3行显示原始文字,搜索高亮显示为TextBlock s。

第4行显示原始文字,搜索高亮显示为RichTextBox