Click here to Skip to main content
15,860,972 members
Articles / Desktop Programming / WPF
Article

OpenXML + FlowDocument = OpenFlowDocument?

Rate me:
Please Sign up or sign in to vote.
4.74/5 (14 votes)
8 Apr 2008CPOL2 min read 91.7K   2.2K   47   11
An article on how to render a Word document in a WPF FlowDocument control by parsing the OpenXML WordML using XLINQ

Introduction

OpenXML is a new standard used by all of Microsoft's new Office suites (Office 2007)! Because it is an open standard and based on XML, we can easily parse documents created with these products. The topic of this article will be how to parse a Word document (using XLINQ) and then render the document in a WPF control called the FlowDocument!

Parsing an OpenXML Document using XLINQ

System.IO.Packaging

The first problem is to extract or unpack the *.docx file into its containing *.xml files.

C#
Package package = Package.Open(filename);
Uri documentUri = new Uri("/word/document.xml", UriKind.Relative);
PackagePart documentPart = package.GetPart(documentUri);
XElement wordDoc = XElement.Load(new StreamReader(documentPart.GetStream()));

The snippet above opens a Word document, extracts the document.xml into an XElement.

Using XLINQ to Get All the Paragraphs

All Word documents require the WordML namespace:

C#
XNamespace w = http://schemas.openxmlformats.org/wordprocessingml/2006/main;

Now we can make a simple XLINQ query to get all the paragraphs (please note: to keep this simple, I am only looking at the paragraphs, I ignore images, drawings, tables, etc.).

C#
var paragraphs = from p in wordDoc.Descendants(w + "p")
                 select p;

Next, we iterate over the collection of paragraphs and display them in a FlowDocument!

FlowDocument

Sacha has a nice article on the basics of FlowDocuments available here!

C#
foreach (var p in paragraphs)
{
    var style = from s in p.Descendants(w + "pPr")
                select s;

    var font = (from f in style.Descendants(w + "rFonts")
                select f.FirstAttribute).FirstOrDefault();
    var size = (from s in style.Descendants(w + "sz")
                select s.FirstAttribute).FirstOrDefault();

    Paragraph par = new Paragraph();
    Run r = new Run(p.Value);
    if (font != null)
    {
        FontFamilyConverter converter = new FontFamilyConverter();
        r.FontFamily = (FontFamily)converter.ConvertFrom(font.Value);
    }
    if (size != null)
    {
        r.FontSize = double.Parse(size.Value);
    }
    par.Inlines.Add(r);

    flowDoc.Blocks.Add(par);
}

For each paragraph, I check if it has a font family or size explicitly set. I then create a new Paragraph and add a Run to its Inlines collection (I also change the font family and size if available). I then add the Paragraph to my FlowDocument!

And that is it!

All that is left now is to find a cool way to extend the normal FlowDocument to support Word document? You can sub-class the FlowDocument... I decided to rather provide it as an extension method!

To load a Word document into a flow document, you first create a FlowDocumentViewer (I created it in XAML):

XML
<FlowDocumentPageViewer x:Name="flowDocViewer" Zoom="80" />

And load the Word document...

C#
FlowDocument flowDoc = new FlowDocument();
flowDoc.loadWordML("DisciplesBios.docx");
flowDocViewer.Document = flowDoc;

I created a simple Word document with all the WPF Disciples bios. Here is how it looks in a FlowDocument:

OpenFlowDocScreen.jpg

Simple and easy...

If you like the article, please vote for it and also visit my blog: http://dotnet.org.za/rudi

History

  • 9th April, 2008: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
South Africa South Africa
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionthe picture in docx can not show? Pin
chicky_china18-Apr-14 15:23
chicky_china18-Apr-14 15:23 
QuestionThat's Great! Pin
Member 124954613-Jan-13 5:21
Member 124954613-Jan-13 5:21 
GeneralMy vote of 5 Pin
vishal katoch4-Dec-12 19:50
vishal katoch4-Dec-12 19:50 
GeneralImage support Pin
Muneer Safi2-Jan-10 22:11
Muneer Safi2-Jan-10 22:11 
GeneralCan't open docx Pin
JustBeFree13-Sep-09 5:39
JustBeFree13-Sep-09 5:39 
GeneralRe: Can't open docx Pin
robmar15-Oct-09 3:47
robmar15-Oct-09 3:47 
GeneralRe: Can't open docx Pin
JustBeFree11-Jan-10 2:52
JustBeFree11-Jan-10 2:52 
GeneralAdding Image & table Pin
yrianto25-Sep-08 20:41
yrianto25-Sep-08 20:41 
GeneralRe: Adding Image & table Pin
Johnny Glenn25-Mar-12 22:16
Johnny Glenn25-Mar-12 22:16 
GeneralNice Pin
User 27100925-Apr-08 9:05
User 27100925-Apr-08 9:05 
GeneralRe: Nice Pin
rudigrobler28-Apr-08 22:00
rudigrobler28-Apr-08 22:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.