How to Implement a Smart Tag System using C1TextParser
We all need to deal with a lot of data in text form every day. Based on the data we read, we decide to take appropriate action. However, only a part of the data carries the information that is useful to us. In search of this small subset of information, we become “human parsers”. What if we could delegate this task to an actual parser?
In this post, we are going to see how we can implement a SmartTag system using one of our Service library: C1TextParser. Smart Tag is a feature initially introduced in Microsoft Word which recognizes parts of text, highlights them in some form, and optionally adds an action which can be performed using that part of the text.
Some of the things which can be augmented using a Smart Tag include a phone number, tracking number, an email, a contact name, etc. By having an application support SmartTags, it allows the end-user to have a feature-rich document that provides the ability to interact with their documents in a way which would be impossible to do with a plain text document.
You can see how useful this can be from the following demo:
By adding a few SmartTags, we're able to:
- See useful information from the document at a glance (the stock ticker, which stocks closed up/down)
- View a summary of a particular stock from the Tooltip
- View price trend for a particular stock by clicking on its symbol
- Add the symbol for a new Stock and immediately do all the things we could do with existing parts of the document
- Compare the Price trend for 2 (or more) Stocks
- Edit a date text anywhere in the document using DatePicker control
So, we have seen what SmartTags can do for us. Let's see how we can implement a SmartTag system using C1TextParser library.
Before we start, we need to decide how and where we are going to have the text information. Since C1TextParser only performs operations on a text stream, we’ll need a document and the ability to manipulate parts of the document visually. C1RichTextBox is perfect for this since it provides APIs to edit and manipulate parts of the document.
Now that we have decided what we are going to use, here’s what we’ll do:
- Create a simple WPF application with C1RichTextBox
- Create a Parser using C1TextParser to create Smart Tags
- Format the created Smart Tags using C1RichTextBox
- Associate an action with the Smart Tag
Create a WPF Application with C1RichTextBox
We first create a WPF application and add C1RichTextBox in MainWindow.xaml:
We also add a simple HTML document which will be loaded in C1RichTextBox:
MainWindow.xaml.cs
document.html
Next, we will make this simple document more interactive by using Smart Tags. For that we'll need a Parser to create these Smart Tags.
Create a Parser Using C1TextParser to Create Smart Tags
Configure C1TextParser
First, we’ll need to install the Nuget package for C1TextParser. We can do so by using the Nuget Package Manager:
Since we have created a WPF application, we install C1.WPF.TextParser.
Create a Smart Tag Template Document
We want our Smart Tag system to be easily modifiable so we are going to create a template for this purpose. C1TextParser’s Template based Extractor is ideal for this purpose, however, we don’t just want to create one Smart Tag, we also want it to be extensible.
We should create a custom template structure which can have the actual parsing template embedded in it.
smart-tag-template.xml
Here, we’ve added two elements for a Smart Tag:
- ParserTemplate – Parsing template used by C1TextParser
- Styles – Styling properties used by C1RichTextBox to highlight the Smart Tag
Create a Utility to Read a Smart Tag Template
Since we created a custom XML document to store configuration for the Smart Tags, we also need something to read this document.
For this purpose, we create a class named TemplateReader:
TemplateReader.cs
We also add a few methods in TemplateReader to get different elements from our Smart Tag template:
TemplateReader.cs
The Styles element is a little different. We will eventually use StyleOverrides of C1RichTextBox to highlight the SmartTags.
We need to create an object of C1TextElementStyle from the Style nodes at runtime. We can do this using reflection:
TemplateReader.cs
Above snippet shows how we can read the value for a Color. Other types of Style properties can be read similarly.
Create Parsers for SmartTags
We have seen how we can store Smart Tag configuration in an XML document and then read it. Now, let’s put it together to create Parsers for the Smart Tags.
Since using Parsers for each type of Smart Tag is quite cumbersome, we abstract this into a single Parser and let it handle all the details about the XML template and its reader.
SmartTagParsers.cs
Here, we created a class named SmartTagParsers which will have IExtractor objects for each type of Smart Tag. IExtractor is the interface used by C1TextParser to parse text, so we just map an IExtractor with a Smart Tag name using the Dictionary object extractors.
We also add a Parse method to our SmartTagParsers which will create a List of SmartTag objects that are found in given text. Since TemplateBasedExtractors parse the result into a JSON object we convert it to a simple SmartTag object.
SmartTag.cs
SmartTagParsers.cs
Finally, we add a GetStyle method which just obtains the Style from the TemplateReader:
SmartTagParsers.cs
Format the Created Smart Tags Using C1RichTextBox
We are now ready to use the Parser with C1RichTextBox. For this, we first create an object of C1RangeStyleCollection and add this in StyleOverrides of C1RichTextBox.
MainWindow.xaml.cs
We then add some methods to parse the document and fill this Style collection for each Smart Tag:
MainWindow.xaml.cs
With these changes, the document looks like this:
Now we can highlight some useful information in the document; however, it would be more helpful if we could do something with these tags. For this, we can associate an Action with a SmartTag.
Associating an Action with a SmartTag
To associate an Action with a Smart Tag we first identify which part of the document is clicked by the user, and if it is a Smart Tag then show some useful information.
We do this using a utility method that identifies the text portion (for a particular Run of the document) currently residing under a given point:
MainWindow.xaml.cs
After this, we add an event handler for C1RichTextBox’s ElementMouseLeftButtonUp event:
MainWindow.xaml.cs
In the handler, we check if the Control key is pressed. If it is, we try to get stock data for the text portion that was clicked. We use a StockService class to get this data from a JSON file, which can be easily modified to use a real-time Stock API.
Once we have the necessary data, we show this in a window where the data is plotted using C1FinancialChart.
Here’s the XAML snippet for the StockTrend window we have used:
StockTrend.xaml
We can interact with the created SmartTags and make it even more useful:
Creating more SmartTags is now easy. We just need to do two things:
- Add the regex and style information in the SmartTag template,
- If required, add an Action for the SmartTag by using necessary events and properties of the editor.
To check the implementation for the demo shown in the beginning of this post, download the sample.