[]
Word for WPF enables you to add TOC to a word document containing text with the respective headers. These headers can then be used to create a TOC.
Note that a class named WordUtils is used in the code given below. It is available in the product sample located at the following location on your system:
Documents\ComponentOne Samples\WPF\WordCreator
You can use this class in your application from the mentioned location.
Add the following lines of code inside the deriving Window class, to generate a random number and use a string reference:
Shared rnd As New Random()
Shared _extension As String = ".rtf"
static Random rnd = new Random();
static string _extension = ".rtf";
The following code creates content and a TOC for a word document with text and headers in it:
' create document
Dim word = New C1WordDocument()
word.Clear()
word.Info.Title = "Document with Table of Contents"
' add title
Dim titleFont As New Font("Tahoma", 24, RtfFontStyle.Bold)
Dim rcPage As Rect = WordUtils.PageRectangle(word)
Dim rc As Rect = WordUtils.RenderParagraph(word, word.Info.Title, titleFont, rcPage, rcPage, False)
rc.Y += 12
' create nonsense document
Dim bkmk = New List()
Dim headerFont As New Font("Arial", 14, RtfFontStyle.Bold)
Dim bodyFont As New Font("Times New Roman", 11)
For i As Integer = 0 To 29
' create ith header (as a link target and outline entry)
Dim header As String = String.Format("{0}. {1}", i + 1, BuildRandomTitle())
rc = WordUtils.RenderParagraph(word, header, headerFont, rcPage, rc, True, _
True)
' save bookmark to build TOC later
Dim pageNumber As Integer = 1
bkmk.Add(New String() {pageNumber.ToString(), header})
' create some text
rc.X += 36
rc.Width -= 36
For j As Integer = 0 To 3 + (rnd.[Next](20) - 1)
Dim text As String = BuildRandomParagraph()
rc = WordUtils.RenderParagraph(word, text, bodyFont, rcPage, rc)
rc.Y += 6
Next
rc.X -= 36
rc.Width += 36
rc.Y += 20
Next
' start Table of Contents
word.PageBreak()
' start TOC on a new page
rc = WordUtils.RenderParagraph(word, "Table of Contents", titleFont, rcPage, rcPage, True)
rc.Y += 12
rc.X += 30
rc.Width -= 40
' render Table of Contents
Dim dottedPen As New C1.WPF.Word.Pen(Colors.Gray, 1.5F)
dottedPen.DashStyle = C1.WPF.Word.DashStyle.Dot
Dim sfRight As New StringFormat()
sfRight.Alignment = HorizontalAlignment.Right
rc.Height = bodyFont.Size * 1.2
For Each entry As String() In bkmk
' get bookmark info
Dim page As String = entry(0)
Dim header As String = entry(1)
' render header name and page number
word.DrawString(header, bodyFont, Colors.Black, rc)
word.DrawString(page, bodyFont, Colors.Black, rc, sfRight)
' connect the two with some dots (looks better than a dotted line)
Dim dots As String = ". "
Dim wid = word.MeasureString(dots, bodyFont).Width
Dim x1 = rc.X + word.MeasureString(header, bodyFont).Width + 8
Dim x2 = rc.Right - word.MeasureString(page, bodyFont).Width - 8
Dim x = rc.X
rc.X = x1
While rc.X < x2
word.DrawString(dots, bodyFont, Colors.Gray, rc)
rc.X += wid
End While
rc.X = x
' move on to next entry
rc = WordUtils.Offset(rc, 0, rc.Height)
If rc.Bottom > rcPage.Bottom Then
word.PageBreak()
rc.Y = rcPage.Y
End If
Next
' get stream to save to
Dim dlg = New SaveFileDialog()
dlg.FileName = "Sample document"
dlg.DefaultExt = ".docx"
dlg.Filter = WordUtils.GetFileFilter(_extension)
Dim dr = dlg.ShowDialog()
If Not dr.HasValue OrElse Not dr.Value Then
Return
End If
' save document
Using stream = dlg.OpenFile()
word.Save(stream, If(dlg.FileName.ToLower().EndsWith(".docx"), FileFormat.OpenXml, FileFormat.Rtf))
End Using
MessageBox.Show("Word Document saved to " + dlg.SafeFileName)
// create document
var word = new C1WordDocument();
word.Clear();
word.Info.Title = "Document with Table of Contents";
// add title
Font titleFont = new Font("Tahoma", 24, RtfFontStyle.Bold);
Rect rcPage = WordUtils.PageRectangle(word);
Rect rc = WordUtils.RenderParagraph(word, word.Info.Title, titleFont, rcPage, rcPage, false);
rc.Y += 12;
// create nonsense document
var bkmk = new List();
Font headerFont = new Font("Arial", 14, RtfFontStyle.Bold);
Font bodyFont = new Font("Times New Roman", 11);
for (int i = 0; i < 30; i++)
{
// create ith header (as a link target and outline entry)
string header = string.Format("{0}. {1}", i + 1, BuildRandomTitle());
rc = WordUtils.RenderParagraph(word, header, headerFont, rcPage, rc, true, true);
// save bookmark to build TOC later
int pageNumber = 1;
bkmk.Add(new string[] { pageNumber.ToString(), header });
// create some text
rc.X += 36;
rc.Width -= 36;
for (int j = 0; j < 3 + rnd.Next(20); j++)
{
string text = BuildRandomParagraph();
rc = WordUtils.RenderParagraph(word, text, bodyFont, rcPage, rc);
rc.Y += 6;
}
rc.X -= 36;
rc.Width += 36;
rc.Y += 20;
}
// start Table of Contents
word.PageBreak(); // start TOC on a new page
rc = WordUtils.RenderParagraph(word, "Table of Contents", titleFont, rcPage, rcPage, true);
rc.Y += 12;
rc.X += 30;
rc.Width -= 40;
// render Table of Contents
C1.WPF.Word.Pen dottedPen = new C1.WPF.Word.Pen(Colors.Gray, 1.5f);
dottedPen.DashStyle = C1.WPF.Word.DashStyle.Dot;
StringFormat sfRight = new StringFormat();
sfRight.Alignment = HorizontalAlignment.Right;
rc.Height = bodyFont.Size * 1.2;
foreach (string[] entry in bkmk)
{
// get bookmark info
string page = entry[0];
string header = entry[1];
// render header name and page number
word.DrawString(header, bodyFont, Colors.Black, rc);
word.DrawString(page, bodyFont, Colors.Black, rc, sfRight);
// connect the two with some dots (looks better than a dotted line)
string dots = ". ";
var wid = word.MeasureString(dots, bodyFont).Width;
var x1 = rc.X + word.MeasureString(header, bodyFont).Width + 8;
var x2 = rc.Right - word.MeasureString(page, bodyFont).Width - 8;
var x = rc.X;
for (rc.X = x1; rc.X < x2; rc.X += wid)
{
word.DrawString(dots, bodyFont, Colors.Gray, rc);
}
rc.X = x;
// move on to next entry
rc = WordUtils.Offset(rc, 0, rc.Height);
if (rc.Bottom > rcPage.Bottom)
{
word.PageBreak();
rc.Y = rcPage.Y;
}
}
// get stream to save to
var dlg = new SaveFileDialog();
dlg.FileName = "Sample document";
dlg.DefaultExt = ".docx";
dlg.Filter = WordUtils.GetFileFilter(_extension);
var dr = dlg.ShowDialog();
if (!dr.HasValue || !dr.Value)
{
return;
}
// save document
using (var stream = dlg.OpenFile())
{
word.Save(stream, dlg.FileName.ToLower().EndsWith(".docx") ? FileFormat.OpenXml : FileFormat.Rtf);
}
MessageBox.Show("Word Document saved to " + dlg.SafeFileName);
The above code adds bookmark to the headers of the text in document. These bookmarks are then used to generate a TOC.
As you can see in the above code, we have used two methods, BuildRandomParagraph and BuildRandomTitle. These methods contain array of strings and return these strings in specified format as shown in the following code. Similarly, you can create your own methods and string values.
Private Shared Function BuildRandomTitle() As String
Dim a1 As String() = "Learning|Explaining|Mastering|Forgetting|Examining|Understanding|Applying|Using|Destroying".Split("|"C)
Dim a2 As String() = "Music|Tennis|Golf|Zen|Diving|Modern Art|Gardening|Architecture|Mathematics|Investments|.NET|Java".Split("|"C)
Dim a3 As String() = "Quickly|Painlessly|The Hard Way|Slowly|Painfully|With Panache".Split("|"C)
Return String.Format("{0} {1} {2}", a1(rnd.[Next](a1.Length - 1)), a2(rnd.[Next](a2.Length - 1)), a3(rnd.[Next](a3.Length - 1)))
End Function
Private Shared Function BuildRandomParagraph() As String
Dim sb As New StringBuilder()
For i As Integer = 0 To 5 + (rnd.[Next](10) - 1)
sb.AppendFormat(BuildRandomSentence())
Next
Return sb.ToString()
End Function
Private Shared Function BuildRandomSentence() As String
Dim a1 As String() = "Artists|Movie stars|Musicians|Politicians|Computer programmers|Modern thinkers|Gardeners|Experts|Some people|Hockey players".Split("|"C)
Dim a2 As String() = "know|seem to think about|care about|often discuss|dream about|hate|love|despise|respect|long for|pay attention to|embrace".Split("|"C)
Dim a3 As String() = "the movies|chicken soup|tea|many things|sushi|my car|deep thoughs|tasteless jokes|vaporware|cell phones|hot dogs|ballgames".Split("|"C)
Dim a4 As String() = "incessantly|too much|easily|without reason|rapidly|sadly|randomly|vigorously|more than usual|with enthusiasm|shamelessly|on Tuesdays".Split("|"C)
Return String.Format("{0} {1} {2} {3}. ", a1(rnd.[Next](a1.Length - 1)), a2(rnd.[Next](a2.Length - 1)), a3(rnd.[Next](a3.Length - 1)), a4(rnd.[Next](a4.Length - 1)))
End Function
csharp
static string BuildRandomTitle() {
string[] a1 = "Learning|Explaining|Mastering|Forgetting|Examining|Understanding|Applying|Using|Destroying".Split('|');
string[] a2 = "Music|Tennis|Golf|Zen|Diving|Modern Art|Gardening|Architecture|Mathematics|Investments|.NET|Java".Split('|');
string[] a3 = "Quickly|Painlessly|The Hard Way|Slowly|Painfully|With Panache".Split('|');
return string.Format("{0} {1} {2}", a1[rnd.Next(a1.Length - 1)], a2[rnd.Next(a2.Length - 1)], a3[rnd.Next(a3.Length - 1)]);
}
static string BuildRandomParagraph() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 5 + rnd.Next(10); i++) {
sb.AppendFormat(BuildRandomSentence());
}
return sb.ToString();
}
static string BuildRandomSentence() {
string[] a1 = "Artists|Movie stars|Musicians|Politicians|Computer programmers|Modern thinkers|Gardeners|Experts|Some people|Hockey players".Split('|');
string[] a2 = "know|seem to think about|care about|often discuss|dream about|hate|love|despise|respect|long for|pay attention to|embrace".Split('|');
string[] a3 = "the movies|chicken soup|tea|many things|sushi|my car|deep thoughs|tasteless jokes|vaporware|cell phones|hot dogs|ballgames".Split('|');
string[] a4 = "incessantly|too much|easily|without reason|rapidly|sadly|randomly|vigorously|more than usual|with enthusiasm|shamelessly|on Tuesdays".Split('|');
return string.Format("{0} {1} {2} {3}. ", a1[rnd.Next(a1.Length - 1)], a2[rnd.Next(a2.Length - 1)], a3[rnd.Next(a3.Length - 1)], a4[rnd.Next(a4.Length - 1)]);
}
The output will look similar to the image given below: