WPF TextBlock 根据搜索条件突出显示某些部分
我有 TextBlock,它动态添加了内联(基本上是一堆斜体或粗体的 Run 对象)。
在我的应用程序中,我有搜索功能。
我希望能够突出显示正在搜索的 TextBlock 文本。
我所说的突出显示是指更改 TextBlock 文本颜色的某些部分(请记住,它可能会一次突出显示多个不同的 Run 对象)。
但它看起来非常不稳定:(
有没有简单的方法来解决这个问题?
I have TextBlock that has Inlines dynamicly added to it (basically bunch of Run objects that are either italic or bold).
In my application I have search function.
I want to be able to highlight TextBlock's text that is in being searched for.
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).
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
这个问题类似于 如何在 WPF 项目控件中显示带有突出显示的查询词的搜索结果
为了回答这个问题,我提出了一种使用 IValueConverter 的方法。 该转换器获取文本片段,将其格式化为有效的 XAML 标记,并使用 XamlReader 将标记实例化为框架对象。
完整的解释相当长,所以我将其发布到我的博客: 突出显示 WPF TextBlock 中的查询术语
This question is similar to How to display search results in a WPF items control with highlighted query terms
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.
The full explanation is rather long, so I've posted it to my blog: Highlighting Query Terms in a WPF TextBlock
我采用了 dthrasers 答案,并消除了对 XML 解析器的需求。 他很好地解释了 他的博客,但是这不需要我添加任何额外的库,这就是我的做法。
第一步,创建一个转换器类:
第二步:
使用 ContentBlock 代替 TextBlock。 将字符串(您将用于 textBlock)传递到内容块,如下所示:
第三步:
确保您传递的文本在要突出显示的文本部分之前包含
|~S~|
,在之后包含|~E~|
。 例如,在此字符串"my text |~S~|is|~E~| good"
中,is
将以黄色突出显示。笔记:
您可以更改运行中的样式来确定文本的突出显示内容和方式
确保将 Converter 类添加到命名空间和资源中。 这可能还需要重建才能工作。
I took dthrasers answer and 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.
Step one, make a converter class:
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:
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"
theis
will be highlighted in yellow.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.
适用于 .NET Framework 4.7-4.8。 可能需要调整才能在较新的 .NET 版本(例如 .NET 6)中工作,请参阅评论。
与其他更容易重用的解决方案的差异
如何使用
Text="blabla"
属性。 而是将您的文本绑定到HighlightTermBehavior.Text="blabla"
。,或者硬编码
添加此类
AddPartToTextBlock()
用于非突出显示文本AddHighlightedPartToTextBlock()
用于突出显示的文本。FontWeights.ExtraBold
,非突出显示的文本是FontWeights.Light
。works in .NET Framework 4.7-4.8. May need adjustments to work in newer .NET versions like .NET 6, see comments.
Differences to other solutions
How to use
Text="blabla"
property of the TextBlock anymore. Instead bind your text toHighlightTermBehavior.Text="blabla"
.or hardcoded
Add this class
AddPartToTextBlock()
for non highlighted textAddHighlightedPartToTextBlock()
for the highlighted text.FontWeights.ExtraBold
and non highlighted text isFontWeights.Light
.奇怪的是,我最近写了一篇文章来解决同样的问题。 它是一个自定义控件,具有与 TextBlock 相同的属性(因此您可以在任何需要的地方将其替换为
TextBlock
),并且它有一个额外的属性,您可以将其绑定到名为HighLightText
,只要在主Text
属性中找到HighLightText
的值(不区分大小写),它就会突出显示。这是一个创建起来相当简单的控件,您可以在这里找到完整的代码作为解决方案:
SearchMatchTextblock(GitHub )
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 calledHighLightText
, and wherever the value ofHighLightText
is found in the mainText
property (case insensitive), it is highlighted.It was a fairly straight-forward control to create, and you can find the full code as a solution here:
SearchMatchTextblock(GitHub)
以下是我通过构建现有的
TextBlock
并添加一个名为SearchText
的新依赖属性得出的结果:在您看来,这是:
Here is what I came up with by building off of the exisiting
TextBlock
and adding a new dependency property namedSearchText
:And in your view, this:
在这里我提出另一种突出显示文本的方法。 我有一个用例,我需要在 WPF 中装饰一堆 C# 代码,但是我不想使用 textBlock.Inlines.Add 类型的语法,而是想动态生成突出显示的 XAML,然后动态添加它到 Canvas 或 WPF 中的其他容器。
因此,假设您想要对以下代码段进行着色并突出显示其中的一部分:
假设在名为 Test.txt 的文件中找到上述代码。
假设您想要将所有 C# 关键字(public、static、void 等)和简单类型(int、string)着色为蓝色,并以黄色突出显示 Console.WriteLine。
步骤 0. 创建一个新的 WPF 应用程序,并在名为 Test.txt 的文件中包含一些与上面类似的示例代码 步骤
1. 创建代码荧光笔类:
步骤 2. 将 Canvas XAML 标记添加到 MainWindow.xaml
步骤 3. 在您的 MainWindow.xaml 中WPF应用程序添加以下代码:(确保test.txt位于正确的位置):
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.
So suppose you want to colorize the following piece of code and also highlight a part of it:
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.
Step 0. Create a new WPF Application and include some sample code similar to above in a file called Test.txt
Step 1. Create a Code Highlighter class:
Step 2. Add a Canvas XAML tag to your MainWindow.xaml
Step 3. In Your WPF Application add the following code: (make sure that test.txt is in the correct location) :
我遇到了类似的问题 - 试图对大量代表报告的演示者实施文本搜索。 该报告最初被写入字符串中,我们利用 FlowDocumentViewer 的内置 ctrl-F - 它不是很好,并且有一些奇怪的选项,但已经足够了。
如果您只是想要类似的东西,您可以执行以下操作:
我们决定进行重写,因为报告与程序的其余部分保持同步,并且基本上每次编辑都会更改它,每次都必须重新创建整个报告意味着这是相当慢的。 我们希望通过转向更新所需的位模型来改进这一点,但需要具有视图模型(而不仅仅是字符串)才能以合理的方式做到这一点! 然而,我们希望在更换报告之前保留搜索功能,并做得更好,并以一种颜色突出显示“当前”搜索位置,并以另一种颜色突出显示其他搜索命中。
这是我的解决方案的简化版本; 一个派生自
TextBlock
的类,添加了HighlightingInformation
类型的依赖属性。 我没有包含名称空间和用途,因为它们很敏感。当更改文本和突出显示列表以更新运行列表时,此类可以绑定到的类型使用 update 方法。 亮点本身看起来像这样:
生成正确的亮点集合是一个单独的问题,我基本上通过将演示者集合视为递归搜索内容的树来解决这个问题 - 叶节点是那些具有内容和其他节点的节点只要有孩子。 如果您深度优先搜索,您会得到您期望的顺序。 然后,您基本上可以在结果列表周围编写一个包装器来跟踪位置。 我不会发布所有代码 - 我在这里的回应是记录如何让 wpf 以 MVP 风格进行多色突出显示。
我在这里没有使用
INotifyPropertyChanged
或CollectionChanged
,因为我们不需要多播更改(例如,一个演示者有多个视图)。 最初,我尝试通过添加一个文本事件更改通知和一个列表事件更改通知(您还必须手动订阅INotifyCollectionChanged
事件)来实现这一点。 然而,我担心事件订阅会导致内存泄漏,而且文本和突出显示的更新不同时出现这一事实导致了问题。这种方法的一个缺点是人们不应该绑定到该控件的 Text 属性。 在真实版本中,我添加了一些检查+异常抛出来阻止人们这样做,但为了清楚起见,我从示例中省略了它!
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.
If you just want something like that you can do the following:
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 TypeHighlightingInformation
. I've not included the namespace and usings as they are sensitive.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:
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.
I haven't used
INotifyPropertyChanged
orCollectionChanged
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 theINotifyCollectionChanged
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.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!
最终编写了以下代码
目前几乎没有错误,但解决了问题
Ended up writing following code
At moment has few bugs, but solves the problem
如果您正在为 ListViewBase 处理 ContainerContentChanging,则可以采用以下方法:WinRT/ContainerContentChanging 的 TextBlock 突出显示
请注意,这代码适用于 Windows RT。 WPF 语法会略有不同。 另请注意,如果您使用绑定来填充 TextBlock.Text 属性,则我的方法生成的文本将被覆盖。 我使用 ContainerContentChanging 来填充目标字段,因为与普通绑定相比,性能显着提高,内存使用也得到改善。 我仅使用绑定来管理源数据,而不是数据视图。
If you are handling ContainerContentChanging for your ListViewBase, you can take the following approach: TextBlock highlighting for WinRT/ContainerContentChanging
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.
以下突出显示搜索方法采用您的 TextBlock 和搜索词,然后返回包含该词或包含该词的单词的块(以紫色突出显示)。
`
The following highlight search method takes your TextBlock and search term then returns your block with this term or words which contain this term highlighted purple.
`
我的要求是突出显示必须完全可以设置样式,而不仅仅是一些预定义的选项:
Mind
HighlightProperty
和TextProperty
使用的PropertyChangedCallback
。XAML:
数据模板:
The requirement I had was highlighting must be fully style-able beyond just a few pre-defined options:
Mind
PropertyChangedCallback
used byHighlightProperty
andTextProperty
.XAML:
DataTemplate:
我发现有一个组件 EasyHighlightTextBlock 可能非常适合解决您的问题。 它使用
来突出显示文本。 像这样:希望对您有所帮助。
There is a component EasyHighlightTextBlock that I found may be quite good to solve your problem. It uses the
<tags></tags>
to highlight the text. Like this:I hope it can be helpful for you.