WPF TextBlock 根据搜索条件突出显示某些部分
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/751741/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF TextBlock highlight certain parts based on search condition
提问by Daniil Harik
I have TextBlock that has Inlines dynamicly added to it (basically bunch of Run objects that are either italic or bold).
我有动态添加了内联的 TextBlock(基本上是一堆斜体或粗体的 Run 对象)。
In my application I have search function.
在我的应用程序中,我有搜索功能。
I want to be able to highlight TextBlock's text that is in being searched for.
我希望能够突出显示正在搜索的 TextBlock 文本。
By highlighting I mean changing certain parts of TextBlock text's color (keeping in mind that it may highlight several different Run objects at a time).
突出显示我的意思是更改 TextBlock 文本颜色的某些部分(请记住,它可能一次突出显示几个不同的 Run 对象)。
I have tried this example http://blogs.microsoft.co.il/blogs/tamir/archive/2008/05/12/search-and-highlight-any-text-on-wpf-rendered-page.aspx
But it seams very unstable :(
但它接缝非常不稳定:(
Is there easy way to solve this problem?
有没有简单的方法可以解决这个问题?
回答by dthrasher
This question is similar to How to display search results in a WPF items control with highlighted query terms
此问题类似于如何使用突出显示的查询词在 WPF 项目控件中显示搜索结果
In answer to that question, I came up with an approach that uses an IValueConverter. The converter takes a text snippet, formats it into valid XAML markup, and uses a XamlReader to instantiate the markup into framework objects.
为了回答这个问题,我想出了一种使用 IValueConverter 的方法。转换器采用文本片段,将其格式化为有效的 XAML 标记,并使用 XamlReader 将标记实例化为框架对象。
The full explanation is rather long, so I've posted it to my blog: Highlighting Query Terms in a WPF TextBlock
完整的解释很长,所以我把它贴到我的博客上:在 WPF TextBlock 中突出显示查询词
回答by SyntaxRules
I took dthrasers answerand took out the need for an XML parser. He does a great job explaining each of the pieces in his blog, However this didn't require me to add any extra libraries, here's how I did it.
我接受了dthrasers 的回答,并消除了对 XML 解析器的需求。他很好地解释了他博客中的每一部分,但是这不需要我添加任何额外的库,这是我如何做到的。
Step one, make a converter class:
第一步,制作一个转换器类:
class StringToXamlConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string input = value as string;
if (input != null)
{
var textBlock = new TextBlock();
textBlock.TextWrapping = TextWrapping.Wrap;
string escapedXml = SecurityElement.Escape(input);
while (escapedXml.IndexOf("|~S~|") != -1) {
//up to |~S~| is normal
textBlock.Inlines.Add(new Run(escapedXml.Substring(0, escapedXml.IndexOf("|~S~|"))));
//between |~S~| and |~E~| is highlighted
textBlock.Inlines.Add(new Run(escapedXml.Substring(escapedXml.IndexOf("|~S~|") + 5,
escapedXml.IndexOf("|~E~|") - (escapedXml.IndexOf("|~S~|") + 5)))
{ FontWeight = FontWeights.Bold, Background= Brushes.Yellow });
//the rest of the string (after the |~E~|)
escapedXml = escapedXml.Substring(escapedXml.IndexOf("|~E~|") + 5);
}
if (escapedXml.Length > 0)
{
textBlock.Inlines.Add(new Run(escapedXml));
}
return textBlock;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException("This converter cannot be used in two-way binding.");
}
}
Step two: Instead of a TextBlock use a ContentBlock. Pass in the string (you would of used for your textBlock) to the content block, like so:
第二步:使用 ContentBlock 代替 TextBlock。将字符串(您将用于 textBlock)传递给内容块,如下所示:
<ContentControl Margin="7,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Content="{Binding Description, Converter={StaticResource CONVERTERS_StringToXaml}, Mode=OneTime}">
</ContentControl>
Step three:
Make sure the text you pass includes |~S~|
before and |~E~|
after the text part you want to be highlighted. For example in this string "my text |~S~|is|~E~| good"
the is
will be highlighted in yellow.
第三步:确保您传递的文本包括您要突出显示的文本部分|~S~|
之前和|~E~|
之后。例如,在此字符串中"my text |~S~|is|~E~| good"
,is
将以黄色突出显示。
Notes:
You can change the style in the run to determine what and how your text is highlighted
Make sure you add your Converter class to your namespace and resources. This might also require a rebuild to get working.
注意:
您可以在运行中更改样式以确定突出显示文本的内容和方式
确保将 Converter 类添加到命名空间和资源中。这可能还需要重建才能工作。
回答by Dean Chalk
By strange coincidence, I have recently written an article that solves the very same problem. It is a custom control that has the same properties as a TextBlock (so you can swap is out for a TextBlock
wherever you need it), and it has an extra Property that you can bind to called HighLightText
, and wherever the value of HighLightText
is found in the main Text
property (case insensitive), it is highlighted.
奇怪的是,我最近写了一篇文章来解决同样的问题。这是一个具有相同的属性为TextBlock的自定义控件(所以你可以互换是出去TextBlock
无论你需要它),它有一个额外的属性,您可以绑定到叫HighLightText
,何地的价值HighLightText
在被发现mainText
属性(不区分大小写),突出显示。
It was a fairly straight-forward control to create, and you can find the article here:
这是一个相当直接的控件创建,你可以在这里找到这篇文章:
WPF TextBlock With Search String Matching
And the full code as a solution here:
以及作为解决方案的完整代码:
回答by Blechdose
Differences to other solutions
与其他解决方案的差异
- easier to reuse -> attached behavior instead of custom control
- MVVM friendly -> no code behind
- works BOTH ways! -> Changing the term to be highlighted OR the text, both updates the highlight in the textblock. The other solutions i checked had the problem, that changing the text does not reapply the highlighting. Only changing the highlighted term/search text worked.
- 更容易重用 -> 附加行为而不是自定义控件
- MVVM 友好 -> 没有背后的代码
- 两种方式都有效!-> 更改要突出显示的术语或文本,都会更新文本块中的突出显示。我检查的其他解决方案有问题,即更改文本不会重新应用突出显示。仅更改突出显示的术语/搜索文本有效。
How to use
如何使用
- IMPORTANT: do NOT use the regular
Text="blabla"
property of the TextBlock anymore. Instead bind your text toHighlightTermBehavior.Text="blabla"
. - Add the attached properties to your TextBlock like that
- 重要提示:不要再使用
Text="blabla"
TextBlock的常规属性。而是将您的文本绑定到HighlightTermBehavior.Text="blabla"
. - 像这样将附加属性添加到您的 TextBlock
<TextBlock local:HighlightTermBehavior.TermToBeHighlighted="{Binding MyTerm}"
local:HighlightTermBehavior.Text="{Binding MyText}" />
or hardcoded
或硬编码
<TextBlock local:HighlightTermBehavior.TermToBeHighlighted="highlight this"
local:HighlightTermBehavior.Text="bla highlight this bla" />
Add this class
添加这个类
- To change the kind of highlighting, just change these Methods:
AddPartToTextBlock()
for non highlighted textAddHighlightedPartToTextBlock()
for the highlighted text. - At the moment highlighted is
FontWeights.ExtraBold
and non highlighted text isFontWeights.Light
. - probably hard to read without an IDE, sorry.
- 要更改突出显示的类型,只需更改这些方法:
AddPartToTextBlock()
对于突出显示的文本的非突出AddHighlightedPartToTextBlock()
显示的文本。 - 目前突出显示的是
FontWeights.ExtraBold
,非突出显示的文本是FontWeights.Light
。 - 如果没有 IDE,可能很难阅读,抱歉。
public static class HighlightTermBehavior
{
public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached(
"Text",
typeof(string),
typeof(HighlightTermBehavior),
new FrameworkPropertyMetadata("", OnTextChanged));
public static string GetText(FrameworkElement frameworkElement) => (string) frameworkElement.GetValue(TextProperty);
public static void SetText(FrameworkElement frameworkElement, string value) => frameworkElement.SetValue(TextProperty, value);
public static readonly DependencyProperty TermToBeHighlightedProperty = DependencyProperty.RegisterAttached(
"TermToBeHighlighted",
typeof(string),
typeof(HighlightTermBehavior),
new FrameworkPropertyMetadata("", OnTextChanged));
public static string GetTermToBeHighlighted(FrameworkElement frameworkElement)
{
return (string) frameworkElement.GetValue(TermToBeHighlightedProperty);
}
public static void SetTermToBeHighlighted(FrameworkElement frameworkElement, string value)
{
frameworkElement.SetValue(TermToBeHighlightedProperty, value);
}
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is TextBlock textBlock)
SetTextBlockTextAndHighlightTerm(textBlock, GetText(textBlock), GetTermToBeHighlighted(textBlock));
}
private static void SetTextBlockTextAndHighlightTerm(TextBlock textBlock, string text, string termToBeHighlighted)
{
textBlock.Text = string.Empty;
if (TextIsEmpty(text))
return;
if (TextIsNotContainingTermToBeHighlighted(text, termToBeHighlighted))
{
AddPartToTextBlock(textBlock, text);
return;
}
var textParts = SplitTextIntoTermAndNotTermParts(text, termToBeHighlighted);
foreach (var textPart in textParts)
AddPartToTextBlockAndHighlightIfNecessary(textBlock, termToBeHighlighted, textPart);
}
private static bool TextIsEmpty(string text)
{
return text.Length == 0;
}
private static bool TextIsNotContainingTermToBeHighlighted(string text, string termToBeHighlighted)
{
return text.Contains(termToBeHighlighted, StringComparison.Ordinal) == false;
}
private static void AddPartToTextBlockAndHighlightIfNecessary(TextBlock textBlock, string termToBeHighlighted, string textPart)
{
if (textPart == termToBeHighlighted)
AddHighlightedPartToTextBlock(textBlock, textPart);
else
AddPartToTextBlock(textBlock, textPart);
}
private static void AddPartToTextBlock(TextBlock textBlock, string part)
{
textBlock.Inlines.Add(new Run {Text = part, FontWeight = FontWeights.Light});
}
private static void AddHighlightedPartToTextBlock(TextBlock textBlock, string part)
{
textBlock.Inlines.Add(new Run {Text = part, FontWeight = FontWeights.ExtraBold});
}
public static List<string> SplitTextIntoTermAndNotTermParts(string text, string term)
{
if (text.IsNullOrEmpty())
return new List<string>() {string.Empty};
return Regex.Split(text, $@"({Regex.Escape(term)})")
.Where(p => p != string.Empty)
.ToList();
}
}
回答by JonnyRaa
I had a similar problem - trying to implement a text search over a load of presenters that basically represent a report. The report was originally written into a string and we were leveraging FlowDocumentViewer's built in ctrl-F - it's not very good and has some wierd options but was sufficient.
我有一个类似的问题 - 试图对基本上代表报告的大量演示者实施文本搜索。该报告最初被写入一个字符串,我们正在利用 FlowDocumentViewer 内置的 ctrl-F - 它不是很好,并且有一些奇怪的选项,但已经足够了。
If you just want something like that you can do the following:
如果您只是想要类似的东西,您可以执行以下操作:
<FlowDocumentScrollViewer>
<FlowDocument>
<Paragraph FontFamily="Lucida Console" FontSize="12">
<Run Text="{Binding Content, Mode=OneWay}"/>
</Paragraph>
</FlowDocument>
</FlowDocumentScrollViewer>
We decided to go for a rewrite as the report is kept in sync with the rest of the program and basically every edit changes it, having to recreate the entire report everytime means that this is quite slow. We wanted to improve this by moving to a update-the-bits-you-need-to model but needed to have view model (rather than just a string) to be able to do that in a sane way! We wanted to preserve the searching functionality before swapping out the report however and go one better and have highlighting of the 'current' search position in one colour and other search hits in another.
我们决定重写,因为报告与程序的其余部分保持同步,基本上每次编辑都会改变它,每次都必须重新创建整个报告意味着这很慢。我们想通过移动到更新你需要的模型来改进这一点,但需要有视图模型(而不仅仅是一个字符串)才能以一种理智的方式做到这一点!然而,我们希望在换出报告之前保留搜索功能,并做得更好,并以一种颜色突出显示“当前”搜索位置,并以另一种颜色突出显示其他搜索结果。
Here's a simplified version of my solution; a class that derives from TextBlock that adds a dependency property of Type HighlightingInformation. I've not included the namespace and usings as they are sensitive.
这是我的解决方案的简化版本;派生自 TextBlock 的类,该类添加了类型 HighlightingInformation 的依赖项属性。我没有包括命名空间和使用,因为它们是敏感的。
public class HighlightingTextBlock : TextBlock
{
public static readonly DependencyProperty HighlightingProperty =
DependencyProperty.Register("Highlighting", typeof (HighlightingInformation), typeof (HighlightingTextBlock));
public HighlightingInformation Highlighting
{
get { return (HighlightingInformation)GetValue(HighlightingProperty); }
set { SetValue(HighlightingProperty, value); }
}
public HighlightingTextBlock()
{
AddValueChangedCallBackTo(HighlightingProperty, UpdateText);
}
private void AddValueChangedCallBackTo(DependencyProperty property, Action updateAction)
{
var descriptor = DescriptorFor(property);
descriptor.AddValueChanged(this, (src, args) => updateAction());
}
private DependencyPropertyDescriptor DescriptorFor(DependencyProperty property)
{
return DependencyPropertyDescriptor.FromProperty(property, GetType());
}
private void UpdateText()
{
var highlighting = Highlighting;
if (highlighting == null)
return;
highlighting.SetUpdateMethod(UpdateText);
var runs = highlighting.Runs;
Inlines.Clear();
Inlines.AddRange(runs);
}
}
The type this class can be bound to uses the update method when it's text and list of highlights are changed to update the list of Runs. The highlights themselves look something like this:
此类可以绑定到的类型在更改文本和高亮列表以更新 Runs 列表时使用 update 方法。亮点本身看起来像这样:
public class Highlight
{
private readonly int _length;
private readonly Brush _colour;
public int Start { get; private set; }
public Highlight(int start, int length,Brush colour)
{
Start = start;
_length = length;
_colour = colour;
}
private string TextFrom(string currentText)
{
return currentText.Substring(Start, _length);
}
public Run RunFrom(string currentText)
{
return new Run(TextFrom(currentText)){Background = _colour};
}
}
To produce the correct collection of highlights is a seperate problem, which I basically solved by treating the collection of presenters as a Tree that you recursively search for content - leaf nodes are those that have content and other nodes just have children. If you search depth-first you get the order you'd expect. You can then basically write a wrapper around the list of results to keep track of the position. Im not going to post all the code for this - my response here it is to document how you can make wpf do multi-coloured highlighting in MVP style.
生成正确的亮点集合是一个单独的问题,我基本上通过将演示者的集合视为递归搜索内容的树来解决这个问题 - 叶节点是那些有内容的节点,而其他节点只有子节点。如果您搜索深度优先,您会得到您期望的顺序。然后,您基本上可以围绕结果列表编写一个包装器来跟踪位置。我不会为此发布所有代码 - 我在这里的回应是记录如何让 wpf 以 MVP 风格进行多色突出显示。
I haven't used INotifyPropertyChanged or CollectionChanged here as we didn't need the changes to be multi-cast (eg one presenter has multiple views). Initially I tried to do that by adding an event changed notification for Text and one for a list (which you also have to manually subscribe to the INotifyCollectionChanged event on). I had concerns about memory leaks from the event subcriptions however and the fact that the updates for the text and the highlights didn't come at the same time made it problematic.
我在这里没有使用 INotifyPropertyChanged 或 CollectionChanged,因为我们不需要将更改进行多播(例如,一个演示者有多个视图)。最初,我尝试通过为 Text 添加一个事件更改通知和一个列表(您还必须手动订阅 INotifyCollectionChanged 事件)来做到这一点。然而,我担心事件订阅会导致内存泄漏,而且文本和高亮显示的更新不是同时出现的这一事实使其成为问题。
The one drawback of this approach is that people shouldn't bind to the Text property of this control. In the real version I have added some checking + exception throwing to stop people from doing this but ommitted it from the example for clarity's sake!
这种方法的一个缺点是人们不应绑定到此控件的 Text 属性。在真实版本中,我添加了一些检查 + 异常抛出来阻止人们这样做,但为了清楚起见,从示例中省略了它!
回答by MarcBalta
Here is what I came up with by building off of the exisiting TextBlock
and adding a new dependency property named SearchText
:
这是我通过构建现有的TextBlock
并添加一个名为 的新依赖属性得出的结论SearchText
:
public class SearchHightlightTextBlock : TextBlock
{
public SearchHightlightTextBlock() : base() { }
public String SearchText { get { return (String)GetValue(SearchTextProperty); }
set { SetValue(SearchTextProperty, value); } }
private static void OnDataChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
TextBlock tb = (TextBlock)source;
if (tb.Text.Length == 0)
return;
string textUpper = tb.Text.ToUpper();
String toFind = ((String) e.NewValue).ToUpper();
int firstIndex = textUpper.IndexOf(toFind);
String firstStr = tb.Text.Substring(0, firstIndex);
String foundStr = tb.Text.Substring(firstIndex, toFind.Length);
String endStr = tb.Text.Substring(firstIndex + toFind.Length,
tb.Text.Length - (firstIndex + toFind.Length));
tb.Inlines.Clear();
var run = new Run();
run.Text = firstStr;
tb.Inlines.Add(run);
run = new Run();
run.Background = Brushes.Yellow;
run.Text = foundStr;
tb.Inlines.Add(run);
run = new Run();
run.Text = endStr;
tb.Inlines.Add(run);
}
public static readonly DependencyProperty SearchTextProperty =
DependencyProperty.Register("SearchText",
typeof(String),
typeof(SearchHightlightTextBlock),
new FrameworkPropertyMetadata(null, OnDataChanged));
}
And in your view, this:
在您看来,这是:
<view:SearchHightlightTextBlock SearchText="{Binding TextPropertyContainingTextToSearch}"
Text="{Binding YourTextProperty}"/>
回答by Alex Begun
Here I present another Approach for highlighting text. I had a use case where I needed to decorate a bunch of C# Code in WPF, however I did not want to use textBlock.Inlines.Add type of syntax, instead I wanted to generate the highlighting XAML on the fly and then dynamically add it to a Canvas or some other container in WPF.
在这里,我介绍了另一种突出显示文本的方法。我有一个用例,我需要在 WPF 中装饰一堆 C# 代码,但是我不想使用 textBlock.Inlines.Add 类型的语法,而是想动态生成突出显示的 XAML,然后动态添加它到 WPF 中的 Canvas 或其他容器。
So suppose you want to colorize the following piece of code and also highlight a part of it:
因此,假设您想为以下代码段着色并突出显示其中的一部分:
public static void TestLoop(int count)
{
for(int i=0;i<count;i++)
Console.WriteLine(i);
}
Suppose the above code is found in a file called Test.txt . Suppose you want to colorize all the C# keywords (public, static, void etc..) and simple types(int, string) in Blue, and Console.WriteLine highlight in yellow.
假设在名为 Test.txt 的文件中找到上述代码。假设您要将所有 C# 关键字(public、static、void 等)和简单类型(int、string)着色为蓝色,并以黄色突出显示 Console.WriteLine。
Step 0. Create a new WPF Application and include some sample code similar to above in a file called Test.txt
步骤 0. 创建一个新的 WPF 应用程序并在名为 Test.txt 的文件中包含一些与上述类似的示例代码
Step 1. Create a Code Highlighter class:
步骤 1. 创建一个代码荧光笔类:
using System.IO;
using System.Text;
public enum HighLightType
{
Type = 0,
Keyword = 1,
CustomTerm = 2
}
public class CodeHighlighter
{
public static string[] KeyWords = { "public", "static", "void", "return", "while", "for", "if" };
public static string[] Types = { "string", "int", "double", "long" };
private string FormatCodeInXaml(string code, bool withLineBreak)
{
string[] mapAr = { "<","<" , //Replace less than sign
">",">" }; //Replace greater than sign
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(code))))
{
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
line = line.Replace("\t", "    "); //Replace tabs
line = line.Replace(" ", " "); //Replace spaces
for (int i = 0; i < mapAr.Length; i += 2)
line = line.Replace(mapAr[i], mapAr[i + 1]);
if (withLineBreak)
sb.AppendLine(line + "<LineBreak/>"); //Replace line breaks
else
sb.AppendLine(line);
}
}
return sb.ToString();
}
private string BuildForegroundTag(string highlightText, string color)
{
return "<Span Foreground=\"" + color + "\">" + highlightText + "</Span>";
}
private string BuildBackgroundTag(string highlightText, string color)
{
return "<Span Background=\"" + color + "\">" + highlightText + "</Span>";
}
private string HighlightTerm(HighLightType type, string term, string line)
{
if (term == string.Empty)
return line;
string keywordColor = "Blue";
string typeColor = "Blue";
string statementColor = "Yellow";
if (type == HighLightType.Type)
return line.Replace(term, BuildForegroundTag(term, typeColor));
if (type == HighLightType.Keyword)
return line.Replace(term, BuildForegroundTag(term, keywordColor));
if (type == HighLightType.CustomTerm)
return line.Replace(term, BuildBackgroundTag(term, statementColor));
return line;
}
public string ApplyHighlights(string code, string customTerm)
{
code = FormatCodeInXaml(code, true);
customTerm = FormatCodeInXaml(customTerm, false).Trim();
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(code))))
{
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
line = HighlightTerm(HighLightType.CustomTerm, customTerm, line);
foreach (string keyWord in KeyWords)
line = HighlightTerm(HighLightType.Keyword, keyWord, line);
foreach (string type in Types)
line = HighlightTerm(HighLightType.Type, type, line);
sb.AppendLine(line);
}
}
return sb.ToString();
}
}
Step 2. Add a Canvas XAML tag to your MainWindow.xaml
步骤 2. 将 Canvas XAML 标记添加到 MainWindow.xaml
<Window x:Class="TestCodeVisualizer.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:TestCodeVisualizer"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Canvas Name="canvas" />
</Window>
Step 3. In Your WPF Application add the following code: (make sure that test.txt is in the correct location) :
步骤 3. 在您的 WPF 应用程序中添加以下代码:(确保 test.txt 位于正确的位置):
using System.Text;
using System.IO;
using System.Windows;
using System.Windows.Markup;
namespace TestCodeVisualizer
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
string testText = File.ReadAllText("Test.txt");
FrameworkElement fe = GenerateHighlightedTextBlock(testText, "Console.WriteLine");
this.canvas.Children.Add(fe);
}
private FrameworkElement GenerateHighlightedTextBlock(string code, string term)
{
CodeHighlighter ch = new CodeHighlighter();
string uc = "<UserControl xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>[CONTENT]</UserControl>";
string content = "<TextBlock>" + ch.ApplyHighlights(code, term) + "</TextBlock>";
uc = uc.Replace("[CONTENT]", content);
FrameworkElement fe = XamlReader.Load(new System.IO.MemoryStream(Encoding.UTF8.GetBytes(uc))) as FrameworkElement;
return fe;
}
}
}
回答by Mark Jones
If you are handling ContainerContentChanging for your ListViewBase, you can take the following approach: TextBlock highlighting for WinRT/ContainerContentChanging
如果您正在为 ListViewBase 处理 ContainerContentChanging,则可以采用以下方法:WinRT/ContainerContentChanging 的 TextBlock 突出显示
Please note that this code is for Windows RT. The WPF syntax will be slightly different. Also note that if you are using binding to populate the TextBlock.Text property, the text generated by my approach will be overwritten. I use ContainerContentChanging to populate target fields because of radically-increased performance and improvements in memory usage, vs. normal binding. I use binding only to manage the source data, not the data view.
请注意,此代码适用于 Windows RT。WPF 语法会略有不同。另请注意,如果您使用绑定来填充 TextBlock.Text 属性,则我的方法生成的文本将被覆盖。我使用 ContainerContentChanging 来填充目标字段,因为与普通绑定相比,性能和内存使用量有了根本的提高。我只使用绑定来管理源数据,而不是数据视图。
回答by Daniil Harik
Ended up writing following code
最终编写了以下代码
At moment has few bugs, but solves the problem
目前有一些错误,但解决了问题
if (Main.IsFullTextSearch)
{
for (int i = 0; i < runs.Count; i++)
{
if (runs[i] is Run)
{
Run originalRun = (Run)runs[i];
if (Main.SearchCondition != null && originalRun.Text.ToLower()
.Contains(Main.SearchCondition.ToLower()))
{
int pos = originalRun.Text.ToLower()
.IndexOf(Main.SearchCondition.ToLower());
if (pos > 0)
{
Run preRun = CloneRun(originalRun);
Run postRun = CloneRun(originalRun);
preRun.Text = originalRun.Text.Substring(0, pos);
postRun.Text = originalRun.Text
.Substring(pos + Main.SearchCondition.Length);
runs.Insert(i - 1 < 0 ? 0 : i - 1, preRun);
runs.Insert(i + 1, new Run(" "));
runs.Insert(i + 2, postRun);
originalRun.Text = originalRun.Text
.Substring(pos, Main.SearchCondition.Length);
SolidColorBrush brush = new SolidColorBrush(Colors.Yellow);
originalRun.Background = brush;
i += 3;
}
}
}
}
}