我最近不得不通过为 TextBlocks 编写混合行为来解决这个问题。
它可以在 XAML 中声明,其中包含突出显示元素的列表,您可以在其中指定要突出显示的文本、您希望该文本的颜色及其字体粗细(可以根据需要轻松添加更多格式属性)。
它的工作原理是循环遍历所需的亮点,扫描 TextBlock 以查找从 TextBlock.ContentStart TextPointer 开始的每个短语。一旦找到该短语,它就可以构建一个 TextRange,它可以应用格式选项。
如果 TextBlock Text 属性也是数据绑定的,它应该可以工作,因为我附加到绑定目标更新事件。
XAML 中的行为代码和示例见下文
public class TextBlockHighlightBehaviour : Behavior<TextBlock>
{
private EventHandler<DataTransferEventArgs> targetUpdatedHandler;
public List<Highlight> Highlights { get; set; }
public TextBlockHighlightBehaviour()
{
this.Highlights = new List<Highlight>();
}
#region Behaviour Overrides
protected override void OnAttached()
{
base.OnAttached();
targetUpdatedHandler = new EventHandler<DataTransferEventArgs>(TextBlockBindingUpdated);
Binding.AddTargetUpdatedHandler(this.AssociatedObject, targetUpdatedHandler);
// Run the initial behaviour logic
HighlightTextBlock(this.AssociatedObject);
}
protected override void OnDetaching()
{
base.OnDetaching();
Binding.RemoveTargetUpdatedHandler(this.AssociatedObject, targetUpdatedHandler);
}
#endregion
#region Private Methods
private void TextBlockBindingUpdated(object sender, DataTransferEventArgs e)
{
var textBlock = e.TargetObject as TextBlock;
if (textBlock == null)
return;
if(e.Property.Name == "Text")
HighlightTextBlock(textBlock);
}
private void HighlightTextBlock(TextBlock textBlock)
{
foreach (var highlight in this.Highlights)
{
foreach (var range in FindAllPhrases(textBlock, highlight.Text))
{
if (highlight.Foreground != null)
range.ApplyPropertyValue(TextElement.ForegroundProperty, highlight.Foreground);
if(highlight.FontWeight != null)
range.ApplyPropertyValue(TextElement.FontWeightProperty, highlight.FontWeight);
}
}
}
private List<TextRange> FindAllPhrases(TextBlock textBlock, string phrase)
{
var result = new List<TextRange>();
var position = textBlock.ContentStart;
while (position != null)
{
var range = FindPhrase(position, phrase);
if (range != null)
{
result.Add(range);
position = range.End;
}
else
position = null;
}
return result;
}
// This method will search for a specified phrase (string) starting at a specified position.
private TextRange FindPhrase(TextPointer position, string phrase)
{
while (position != null)
{
if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
{
string textRun = position.GetTextInRun(LogicalDirection.Forward);
// Find the starting index of any substring that matches "phrase".
int indexInRun = textRun.IndexOf(phrase);
if (indexInRun >= 0)
{
TextPointer start = position.GetPositionAtOffset(indexInRun);
TextPointer end = start.GetPositionAtOffset(phrase.Length);
return new TextRange(start, end);
}
}
position = position.GetNextContextPosition(LogicalDirection.Forward);
}
// position will be null if "phrase" is not found.
return null;
}
#endregion
}
public class Highlight
{
public string Text { get; set; }
public Brush Foreground { get; set; }
public FontWeight FontWeight { get; set; }
}
XAML 中的示例用法:
<TextBlock Text="Here is some text">
<i:Interaction.Behaviors>
<behaviours:TextBlockHighlightBehaviour>
<behaviours:TextBlockHighlightBehaviour.Highlights>
<behaviours:Highlight Text="some" Foreground="{StaticResource GreenBrush}" FontWeight="Bold" />
</behaviours:TextBlockHighlightBehaviour.Highlights>
</behaviours:TextBlockHighlightBehaviour>
</i:Interaction.Behaviors>
</TextBlock>
您需要导入 Blend 交互命名空间和行为的命名空间:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:behaviours="clr-namespace:YourProject.Behviours"