Gembox document removes table of contents - c#

I'm using Gembox document to replace some text in a docx document and it works great. However, I have a table of contents field that disappears after saving the document.
I tried doing the following but the field still disappears leaving only the placeholder text:
var toc = (TableOfEntries)document.GetChildElements(true, ElementType.TableOfEntries).First();
toc.Update();
document.GetPaginator(new PaginatorOptions() { UpdateFields = true });

UPDATE (2021-01-15):
Please try again with the latest version from the BugFixes page or from NuGet.
The latest version will work on the machine that uses culture with ';' character as a list separator.
Or you can specify that culture like this:
var toc = (TableOfEntries)document.GetChildElements(true, ElementType.TableOfEntries).First();
CultureInfo.CurrentCulture = new CultureInfo("fr");
toc.Update();
document.GetPaginator(new PaginatorOptions() { UpdateFields = true });
Also, the issue with the missing tab stop should be resolved now as well.
ORIGINAL:
When I tried to update your TOC from MS Word, I got the following:
No table of contents entries found.
After investigating the field's code of your TOC element, I figured out what the problem is.
This is the instruction text that you have:
{ TOC \h \z \t "TitreChapitre;1;SousTitreChapitre;2" }
These semicolon character separators (;) are culture-dependent. In other words, updating this TOC element will work on a machine that has a French region and settings, but it won't work when you have an English region and settings.
I'm currently on vacation, so I can't do anything about this. When I come back I will fix this problem for you.
For now, can you use the following as a workaround (I also noticed an issue with missing TabStop, this workaround will cover that as well):
var toc = (TableOfEntries)document.GetChildElements(true, ElementType.TableOfEntries).First();
var section = toc.Parent as Section;
var tocWidth = section.PageSetup.PageWidth - section.PageSetup.PageMargins.Left - section.PageSetup.PageMargins.Right;
var toc1Style = document.Styles["toc 1"] as ParagraphStyle;
var toc1TabStop = new TabStop(tocWidth - toc1Style.ParagraphFormat.RightIndentation, TabStopAlignment.Right, TabStopLeader.Dot);
toc1Style.ParagraphFormat.Tabs.Add(toc1TabStop);
var toc2Style = document.Styles["toc 2"] as ParagraphStyle;
var toc2TabStop = new TabStop(tocWidth - toc2Style.ParagraphFormat.RightIndentation, TabStopAlignment.Right, TabStopLeader.Dot);
toc2Style.ParagraphFormat.Tabs.Add(toc2TabStop);
toc.InstructionText = toc.InstructionText.Replace(';', ',');
toc.Update();
document.GetPaginator(new PaginatorOptions() { UpdateFields = true });
I hope this works for you.

Related

Handlebars.Net with local File path

I have a configuration value that represents a folder where some files are available for download. This value is a handlebars template:
"D:\{{identifier1}}\{{identifier2}}\SomeFolder\{{version}}"
This value is set per environment by our deploy server.
The problem is that when I run the template through like this:
var template = Handlebars.Compile(_configuration.FilePathFormat);
return template(new
{
identifier1 = 123,
identifier2 = 456,
version = "latest"
});
The result I get back is this:
R:{{identifier1}}{{identifier2}}\SomeFolder{{version}}
What I expect:
R:\123\456\SomeFolder\latest
For some reason it is escaping the handlebars and I don't want that. I have been unable to find anything on disabling escape characters, and no amount of slashes has worked to render the template correctly.
Also, if I put a space between the slash and the handlebar placeholder, it compiles and renders correctly, but then it has a space in the file path.
I found a site that let me test handlebars.js, but it behaves differently than handlebars.net
Update: Fixed in Handlebars.net
Sice version 1.9.3, released right after I reported the bug, this now works just fine. You have to double your slashes in the template to escape them for Handlebars.Net, same as for Handlebars.js,
var templateText = #"D:\\{{identifier1}}\\{{identifier2}}\\SomeFolder\\{{version}}";
var compiledTemplate = Handlebars.Compile(templateText);
var path = compiledTemplate(new
{
identifier1 = 123,
identifier2 = 456,
version = "latest"
});
Original answer:
Yes, it seems Handlebars.net has some weird handling of escape characters.
The simplest workaround is to just invert the slashes in the template string.
var templateText = #"D:/{{identifier1}}/{{identifier2}}/SomeFolder/{{version}}";
var compiledTemplate = Handlebars.Compile(templateText);
var pathWithInvertedSlashes = compiledTemplate(new
{
identifier1 = 123,
identifier2 = 456,
version = "latest"
});
// Inverted slashes normally work fine on Windows, but if you want to
// 'fix' them you can always do
var canonicalPath = Path.GetFullPath(pathWithInvertedSlashes);

Bold Specific Elements from JSON Array in Rich Textbox

I'm currently facing an issue with the formatting of a chunk of text which is retrieved from a webserver as a JSON array.
What I am trying to acomplish is to format the text in a way that can be easily read by the user. An Example output of what I am trying to achieve is:
This is a Title
This is a little informative paragraph based on the subject selected
This is a secondary title
This is another paragraph
The way the string looks (before modification):
{"Title":"This is a Title", "Content_One": "This is alittle
informative paragraph based on the subject selected", "Title_Two":
"This is another paragraph"}
My current application is using Winforms, and I'm attempting to pump this into a Rich Text Box (hopefully going to handle the correct formatting). As a little long shot, I tried returning HTML Tags (Very long shot) For this to provide no change to the text.
I have also tried individually iterating through the array, and attempting to pramatically bold out certain elements from the JSON Array. None of which I have tried have provided expected output.
Attempt one:
TTKNormalContent.Text = new Font(ReturnArr.Title, FontStyle.Bold).ToString();
Which returns:
An unhandled exception of type
'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in
System.Core.dll
Attempt one:
TTKNormalContent.Text = ReturnArr.Title;
TTKNormalContent.SelectionFont = new Font(this.Font, FontStyle.Bold);
Which does not bold out the text
Attempt Two:
I can temporarily make the text bold by:
TTKNormalContent.Font = new Font(TTKNormalContent.Font, FontStyle.Bold);
TTKNormalContent.Text = ReturnArr.Title;
But adding:
TTKNormalContent.Font = new Font(TTKNormalContent.Font, FontStyle.Regular);
TTKNormalContent.Text += ReturnArr.ContentOne;
Which will remove the boldness
You need to use AppendText. When you use Text+= "something" you replace the format.
You can use this example:
var json = "{\"Title\":\"This is a Title\", \"Content_One\": \"This is alittle informative paragraph based on the subject selected\", \"Title_Two\": \"This is another paragraph\"}";
var start = 0;
Dictionary<string, string> values = new JavaScriptSerializer().Deserialize<Dictionary<string, string>>(json);
values.Cast<KeyValuePair<string, string>>()
.ToList()
.ForEach(item =>
{
this.richTextBox1.AppendText(item.Key);
this.richTextBox1.AppendText( ":" );
start += item.Key.Length + 1;
this.richTextBox1.AppendText(item.Value);
this.richTextBox1.Select(start, item.Value.Length);
this.richTextBox1.SelectionFont = new Font(this.richTextBox1.Font, FontStyle.Bold);
this.richTextBox1.AppendText("\n");
start += item.Value.Length + 1;
});
Screenshot:

Cannot change hyperlink style with Word interop without changing the style of the next paragraph

I have a document with a format similar to
Section Heading 1
Paragraph 1
...
Paragraph N
Sub Heading 1
Paragraph 1
...
Paragraph N
What I am trying to do is add a hyperlink from a heading to a reference document. I can add the hyperlink and apply a style to the link but the style gets applied to the section's Paragraph 1 as well as the hyperlink.
Note: WordApp is a singleton wrapper around Microsoft.Office.Interop.Word.Application. The HyperlinkDestionation class just holds the bookmark name and the path for the file that contains the bookmark.
private void LinkHeadings(string file)
{
Document doc = WordApp.Open(file);
for (int i = 1; i <= proposal.Paragraphs.Count; i++)
{
HyperlinkDestination dest = null;
Paragraph paragraph = proposal.Paragraphs[i];
paragraph.Range.Select();
Style style = (Style)paragraph.get_Style();
string styleString = ((Style)paragraph.get_Style()).NameLocal;
string headingText = paragraph.Range.Text.Split(' ')[0];
if (styleString.Contains("Heading"))
{
dest = _hyperlinkDestinations.Find(x => x.HyperlinkText == headingText);
}
if (dest != null)
{
Hyperlink link = WordApp.ActiveWindow.Document.Hyperlinks.Add(WordApp.Selection.Range, Address: dest.FilePath, SubAddress: dest.bookmarkName, TextToDisplay: WordApp.Selection.Text);
link.Range.set_Style(style);
}
}
WordApp.Close(true);
}
My guess is that it has something to do with with the hyperlink anchor. I've also tried deleting the heading first then inserting the hyperlink but it also has the same result.
The basic problem is that you are including the paragraph mark in the Hyperlink field that Word inserts. That pargraph mark will then be hidden when the hyperlink field result is displayed, i.e. the Section Heading 1 para. will actually become part of Paragraph 1. When you apply the style to the selection, the entire paragraph will be affected.
I'm not going to attempt to provide C# here, but here are some suggestions
a. as a rule it is better to work with Range objects in Word than the Selection where possible, and you should be able to do so here.
b. If you apply the Hyperlink to the paragraph without the paragraph marker, the paragraph style will be unchanged, so you should not need to re-apply it
c. So instead of the code starting with "paragraph.Range.Select();" you should be able to use something like this (I leave you to get the C# syntax right - perhaps you can edit this message)
Range r = Paragraph.Range();
string headingText = r.Text.Split(' ')[0];
if (styleString.Contains("Heading"))
// you shoul probably also tst for an empty paragraph here before inserting anything (I leave it to you)
{
dest = _hyperlinkDestinations.Find(x => x.HyperlinkText == headingText);
}
if (dest != null)
{
// Move the end of the range one character towards the beginning
r.MoveEnd(Word.WdUnits.WdCharacter,-1)
Hyperlink link = WordApp.ActiveWindow.Document.Hyperlinks.Add(r, Address: dest.FilePath, SubAddress: dest.bookmarkName, TextToDisplay: r.Text);
}
If your code needs to run internationally and you only need to check paragraphs with the built-in style types Heading 1..Heading 9, then it would also be better to compare the Style.Type to see if it is one of those 9 style types. If you have other style types called "Heading something" that need to be included, then you probably need to check both the Style.Type and the name.

How to add text into Word Documents at a specific position?

How do I write to a specific position in a Word document, for example, line 5, character 50? I have searched for a couple of hours, but couldn't find a solution.
I am using Microsoft.Office.Interop.Word
If you are content with the more simple sentence, rather than lines:
ActiveDocument.Sentences(1).Characters(5).Select
Selection.Collapse
Selection.InsertBefore "added "
Five paragraphs and 50 spaces in VBA
Selection.Text = String(5, vbCrLf)
Selection.Collapse wdCollapseEnd
Selection.Text = String(50, " ")
However, for a particular position, I would prefer a textbox:
Set sh = doc.Shapes.AddTextbox(1, 10, 344, 575, 80)
sh.Name = "Course1"
With some properties:
sh.Fill.Visible = False
sh.Line.Visible = False
sh.TextFrame.MarginLeft = 0#
sh.TextFrame.MarginRight = 0#
sh.TextFrame.MarginTop = 0#
sh.TextFrame.MarginBottom = 0#
If you will be inserting text at the same location every time a simple way to do this is to create a .dotx template file with a bookmark at the location. Make sure the template is included in the build
Doc = Word.Documents.Add("Directory\Filename")
Doc.Bookmarks.Item("BookmarkName").Range.Text = "Text to be inserted"
Finding a position in a word document to insert a table
You may find some useful information in the above location.

Can't get CJKAnalyzer/Tokenizer to recognise japanese text

i'm working with Lucene.NET and it's great. then worked on how to get it to search asian languages. as such, i moved from the StandardAnalyzer to the CJKAnalyzer.
this works fine for korean (although StandardAnalyzer worked ok for korean!), and chinese (which did not), but i still cannot get the program to recognise japanese text.
just as a very small example, i write a tiny database (using the CJKAnalyzer) with a few words in it, then try and read from the database:
public void Write(string text, AnalyzerType type)
{
Document document = new Document();
document.Add(new Field(
"text",
text,
Field.Store.YES,
Field.Index.ANALYZED));
IndexWriter correct = this.chineseWriter;
correct.AddDocument(document);
}
that's for the writing. and for the reading:
public Document[] ReadMultipleFields(string text, int maxResults, AnalyzerType type)
{
Analyzer analyzer = this.chineseAnalyzer;
QueryParser parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_29, "text", analyzer);
var query = parser.Parse(text);
// Get the fields.
TopFieldCollector collector = TopFieldCollector.create(
new Sort(),
maxResults,
false,
true,
true,
false);
// Then use the searcher.
this.searcher.Search(
query,
null,
collector);
// Holds the results
List<Document> documents = new List<Document>();
// Get the top documents.
foreach (var scoreDoc in collector.TopDocs().scoreDocs)
{
var doc = this.searcher.Doc(scoreDoc.doc);
documents.Add(doc);
}
// Send the list of docs back.
return documents.ToArray();
}
whereby chineseWriter is just an IndexWriter with the CJKAnalyzer passed in, and chineseAnalyzer is just the CJKAnalyzer.
any advice on why japanese isn't working? the input i send seems fair:
プーケット
is what i will store, but cannot read it. :(
EDIT: I was wrong... Chinese doesn't really work either: it the search term is longer than 2 characters, it stops working. Same as Japanese.
EDIT PART 2: I've now seen that the problem is using the prefix search. If I search for the first 2 characters and use an asterisk, then it works. As soon as I go over 2, then it stops to work. i guess this is because of the way the word is tokenized? If I search for the full term, then it does find it. Is there anyway to use prefix search in Lucene.NET for CJK? プ* will work, but プーケ* will find nothing.
I use StandardTokenizer. Atleast for Japanese and Korean text it is able to tokenize the words which contains 3 character or 4. But only worry is for Chinese character. It does tokenize the Chinese language but 1 character at a time.

Categories

Resources