Intro

An AdventureWorks Product Catalog with formatting, tables, lists, nested data, and images.

Create a product catalog by writing data into sections of an existing Word document. This sample demonstrates writing data from a database, formatting, nested Word lists, Word tables, and image insertion

Code

 private WordApplication wwapp;
private Document doc;
private Font charFormat;
// The three major product categories 
string[] categories = { "Component", "Clothing", "Accessory" };
private bool bCategoriesOnNewPage = true;
// This DataTable will store all the product details 
private DataTable data;

/// <summary>
/// Build the report with WordTemplate
/// </summary>
public void GenerateDocument()
{       
 // Create an instance of WordApplication and open the template document 
 wwapp = new WordApplication();

 string templatePath = @"..\..\WordTemplateFiles\ProductCatalogTemplate.doc";
 doc = wwapp.Open(templatePath);

 // This document has three existing sections.
 // The title page, the welcome letter page, and the 
 // blank section where the catalog items should be started.

 Section secTitlePg = doc.Sections[0];
 Section secWelcomePg = doc.Sections[1];
 Section secCatalogPg = doc.Sections[2];

 // Get a reference to the base style and set up a CharacterFormat
 // object for use throughout this class.

 NamedStyle baseStyle = doc.Styles[NamedStyle.BuiltIn.Normal];
 charFormat = baseStyle.Font;
 charFormat.FontName = "Arial";

 // Add the current date to the first section 
 AddGeneratedDate(secTitlePg);

 // Add a bulleted list to the second section.
 // Bulleted items will be numbered.

 AddList(secWelcomePg, true);
 // Add the catalog items to the third section 

 // Populate data DataTable
  // GetCSVData() is a helper method for parsing .csv files
  
 data = GetCSVData(@"..\..\WordData\ProductCatalog2.csv");

 AddCatalog(secCatalogPg);

 // Save the document by streaming it to the client's browser 
 wwapp.Save(doc, @"..\..\WordOutputFiles\ProductCatalog_out.doc");
}


/// <summary>
/// Add the date string to the provided Range.
/// Date will be written in the form: "Jan 1, 2009"
/// </summary>
/// <param name="rng">Element into which the date should be written</param>
private void AddGeneratedDate(Element rng)
{
 DateTime dt = DateTime.Now;
 string datestring = String.Format("{0}/{1}/{2}", dt.Month, dt.Day, dt.Year);
 rng.InsertTextAfter(datestring, false);
}

/// <summary>
/// Add the bulleted list of requested categories 
/// and subcategories to the provided Range.  
/// </summary>
/// <param name="rng">Element into which the list should be written</param>
/// <param name="bNumbered">Numbered (ordered) list</param>
private void AddList(Element rng, bool bNumbered)
{
 // Add line breaks 
 rng.InsertParagraphAfter(null);
 rng.InsertParagraphAfter(null);

 // Create the List 
 List list = rng.InsertListAfter(bNumbered);

 // Loop for every selected category 
 for (int iCat = 0; iCat < categories.Length; iCat++)
 {
 // Add the category text to the first level of the outline.
 // Make the font bold-faced.

 CharacterRun categoryRun =
 list.AddEntry(0).InsertTextAfter(categories[iCat], charFormat);
 categoryRun.Font.Bold = true;

 // Get a list of product subcategories from the major
 // category name.

 string[] subCats = GetProductSubCategories(categories[iCat]);

 // Loop for every subcategory in the current category 
 for (int iSubCat = 0; iSubCat < subCats.Length; iSubCat++)
 {
 // Add the subcategory text to the second
 // level of the outline.

 ListEntry li = list.AddEntry(1);

 //li.LineNumberingAllowed = true;
 li.InsertTextAfter(subCats[iSubCat], charFormat);
 } // for each subcategory
 } // for each category
}

/// <summary>
/// Add the main product catalog to the provided Range.
/// </summary>
/// <param name="rng">Element into which the catalog will be written</param>
private void AddCatalog(Element rng)
{   
 // Loop for every major category chosen 
 for (int iCat = 0; iCat < categories.Length; iCat++)
 {
 // Get the category name from the array categories 
 string catName = categories[iCat];

 // Insert a table 1row x 1col. This table will 
 // hold the header text for every major category.

 Table catTbl = doc.InsertTableAfter(1, 1);

 // Write the major category name into the table cell.
 // Set cell background and font appearance.

 CharacterRun catRun =
 catTbl[0, 0].InsertTextAfter(catName, charFormat);
 catTbl[0, 0].Shading.BackgroundColor = System.Drawing.Color.Gray;
 catRun.Font.Bold = true;
 catRun.Font.Italic = true;
 catRun.Font.FontSize = 26.0f;

 // Get subcategory names for the current category 
 string[] subCats = GetProductSubCategories(catName);
// Marker

//                // Loop once for every subcategory in the current category 
 for (int iSubCat = 0; iSubCat < subCats.Length; iSubCat++)
 {
 doc.InsertParagraphAfter(null);
 string subCat = subCats[iSubCat];

 // Insert a smaller header for the subcategory 
 CharacterRun subCatRun =
 doc.InsertParagraphAfter(null).InsertTextAfter(subCat, charFormat);
 subCatRun.Font.Bold = true;
 subCatRun.Font.FontSize = 22.0f;
// GetProductCatalogData
 // Get a list of products in the current subcategory 
 DataTable dtProducts = GetProductCatalogData(subCat);


 // Loop for every product in the subcategory 
 //REFINE THIS COMMENT
 foreach (DataRow dr in dtProducts.Rows)
 {
 // Insert a table to hold product data 
 Table prodTbl = doc.InsertTableAfter(4, 2);

 // Merge the top row of cells 
 prodTbl[0, 0].FirstMerged = true;
 prodTbl[0, 1].Merged = true;

 // Add the product name and set font appearance 
 CharacterRun titleRun =
 prodTbl[0, 0].InsertTextAfter(dr["Name"].ToString(), charFormat);
 titleRun.Font.FontSize = 18.0f;
 titleRun.Font.Bold = true;
 titleRun.Font.Italic = true;
 titleRun.Font.TextColor = System.Drawing.Color.Blue;

 // Add product description to the next row 
 prodTbl[1, 0].InsertTextAfter(dr["Description"].ToString(), charFormat);

 // InsertImageAfter method 
 if (dr["ThumbNailPhoto"].ToString() != "")
 {
 InlineImage image = prodTbl[1, 1].InsertImageAfter(@"..\..\WordImages\ProductCatalogImages\" + dtProducts.Rows[dtProducts.Rows.IndexOf(dr)]["ThumbNailPhoto"]);
 double width = image.Width;
 double height = image.Height;
 Console.WriteLine("W: " + image.Width + ", H: " + image.Height);

 image.Height=(int)( height//(2000 / width));
 image.Width=2000;

 Console.WriteLine("W: "+image.Width+", H: "+image.Height);
 }

 // Write the rest of the product details into the table 
 prodTbl[2, 0].InsertTextAfter("Product Number", charFormat).Font.Bold = true;
 prodTbl[3, 0].InsertTextAfter(dr["ProductNumber"].ToString(), charFormat);
 prodTbl[2, 1].InsertTextAfter("Price", charFormat).Font.Bold = true;
 prodTbl[3, 1].InsertTextAfter("$" + dr["Price"].ToString(), charFormat);
    
   }

    }

 // If it was chosen to put categories on new pages,
 // AND if the last category hasn't just been written,
 // add a section/page break.

 if (bCategoriesOnNewPage && (iCat < categories.Length - 1))
 {
 Section sec = doc.CreateSectionAfter();
 sec.Break = Section.BreakType.Page;
 }
 }
}

/// <summary>
/// Set document property metadata for the catalog document
/// </summary>
private void AddDocProperties()
{
 // Get the DocumentProperties interface from Document 
 DocumentProperties docprops = doc.DocumentProperties;

 // Set built-in DocumentProperties values 
 docprops.Author = "John Doe";
 docprops.Comments = "A basic demonstration of OfficeWriter for Word";
 docprops.Company = "SoftArtisans, Inc.";
 docprops.Title = "Basic Word Document";

 // Set custom DocumentProperties key/value pairs 
 docprops.SetCustomProperty("GeneratedBy", "SoftArtisans OfficeWriter for Word");
}

/// <summary>
/// Get a list of products for a subcategory.
/// </summary>
/// <param name="subCat">Subcategory name to look up</param>
/// <returns>DataTable of product from the provided subcategory</returns>
private DataTable GetProductCatalogData(string subCat)
{
 DataTable dt = new DataTable();
 dt.Columns.Add("Name");
 dt.Columns.Add("Description");
 dt.Columns.Add("ProductNumber");
 dt.Columns.Add("Price");
 dt.Columns.Add("ThumbNailPhoto");

 //find data
 int iRow = 0;
 while (iRow < data.Rows.Count)
 {
 if (data.Rows[iRow]["Subcategory"].ToString() == subCat)
 {
 dt.ImportRow(data.Rows[iRow]);
 }
 iRow++;
 }
 return dt;
}

/// <summary>
/// Get a list of subcategory names for the provided major category.
/// </summary>
/// <param name="cat">Category to look up</param>
/// <returns>Array of product subcategory strings</returns>
private string[] GetProductSubCategories(string cat)
{
 ArrayList al = new ArrayList();
 if (cat == "Clothing")
 {
 al.AddRange(new string[]{"Bib-Shorts","Caps","Gloves","Jerseys","Shorts","Socks","Tights","Vests"});
 }
 if (cat == "Component")
 {
 al.AddRange(new string[]{"Handlebars","Bottom Brackets","Brakes","Chains","Cranksets","Derailleurs","Forks","Headsets","Mountain Frames","Pedals","Road Frames","Saddles","Touring Frames","Wheels"});

 }
 if (cat == "Accessory")
 {
 al.AddRange(new string[]{ "Bike Racks","Bike Stands","Bottles and Cages","Cleaner","Fenders","Helmets","Hydration Packs","Lights","Locks","Panniers","Pumps","Tires and Tubes"});
 }
 return (string[])al.ToArray(typeof(string));
}
#region Utility Methods
//Uses CSV reader
System.Data.DataTable GetCSVData(string csvFileName)
{
 DataTable dt;
 using (GenericParserAdapter parser = new GenericParserAdapter(csvFileName))
 {
 parser.ColumnDelimiter = ',';
 parser.FirstRowHasHeader = true;
 dt = parser.GetDataTable();
 }
 return dt;
}

#endregion

Downloads

Template: ProductCatalogTemplate.doc

Output: ProductCatalog_out.doc