在WPF应用程序RichTextBox中,我正在尝试找到一种方法来为框内的各种单词提供背景颜色。在RichTextBox的System.Windows.Forms版本中,有一种非常简单的方法:
richTextBox1.SelectionBackColor = color;
richTextBox1.AppendText(word);
但是,RichTextBox的System.Windows.Controls版本只有SelectionBrush,并且这种方法不起作用。
RichTextBox中不同单词的背景颜色是否可能?
答案 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
。