by James Newton-King
DrawingML is the graphics markup language used in Office Open XML documents. Unlike the standalone WordprocessingML and PresentationML languages which represent docx and pptx documents, DrawingML is always embedded inside another mark-up language as content. DrawingML is used throughout all Office Open documents to display vector graphics, from text effects to complex 3D charts.
In this article we are going to examine how to generate simple DrawingML shapes. The application that we’re going to build iterates on a previous Open XML Developer application, a Silverlight Word document generator. We’ll and add a simple painting surface to Silverlight and render the shapes drawn in Silverlight as DrawingML graphics to the final generated document.
Implementing the Silverlight UI
A lot of the code from the Silverlight Word document generator can be reused, especially code to do with generating the Word document. Most of the changes here are to the Silverlight UI and adding a surface to draw shapes on it. Let’s break down the new Silverlight UI.
From top to the bottom of the screen are the following components:
1. The Title Textbox. The content of this Silverlight textbox will be inserted as a title to the generated Word document
2. The Drawing Canvas. This is a Silverlight Canvas with events attached to capture user mouse actions. On mouse down a shape will be created and placed on the drawing surface at the mouse location.
private void DrawingCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!_drawing)
_drawing = true;
_startingPoint = e.GetPosition(DrawingCanvas);
_shape = CreateShape((ShapesList.SelectedIndex == 0) ? ShapeType.Rectangle : ShapeType.Oval);
_shape.Fill = new SolidColorBrush((Color)ColorsList.SelectedItem);
Canvas.SetLeft(_shape, _startingPoint.X);
Canvas.SetTop(_shape, _startingPoint.Y);
DrawingCanvas.Children.Add(_shape);
}
As the mouse moves the shape will be resized around this origin location, growing and shrinking in size. Finally when the user is happy with the shape an event is raised for mouse up and the shape is marked as finished drawing, making the canvas ready for the next shape.
3. The Shape and Color selectors. These two controls are restyled Silverlight ListBoxes. The Colors ListBox is databound from a collection of colors defined in the code-behind. The Shapes selector is another ListBox containing two list items: a Square and a Circle. The colors of the two shapes are databound to the Color listbox and will change with the selected color.
4. The Clear, Party Fiesta and Save buttons. The Clear button simply clears the child controls of the Drawing Canvas. The Party Fiesta button draws 10 random shapes on the Drawing Canvas. Finally the Save button generates the Word document.
Generating the Open XML Word Document
Document generation reuses Chris Klug’s fantastic Silverlight Open XML library. Let’s take a look at the Save button source code:
private void SaveButton_Click(object sender, RoutedEventArgs e)
SaveFileDialog dlg = new SaveFileDialog();
dlg.Filter = "Word Document (.docx)|*.docx|Zip Files (.zip)|*.zip";
dlg.DefaultExt = ".docx";
if (dlg.ShowDialog() == true)
WordDocument doc = new WordDocument();
doc.ApplicationName = "SLPaint";
doc.Creator = "James Newton-King";
doc.Company = "Intergen";
AddDocumentHeadline(doc.Document);
AddDocumentShapes(doc.Document);
using (IStreamStorage storage = new ZipStreamStorage(dlg.OpenFile()))
doc.Save(storage);
A SaveFileDialog needs to be displayed to the user to save the generated document to the file system. Once the user has confirmed a valid file name and clicked ok the actual document generation happens.
Using the Silverlight Open XML library generating the title is a simple matter of creating a new Run object and then adding a Text object with the content set to the Silverlight Title textbox:
private void AddDocumentHeadline(DocumentPart doc)
Run r = doc.CreateElement<Run>();
Text t = doc.CreateElement<Text>();
t.Content = Headline.Text;
r.Content.Add(t);
doc.Sections[0].Paragraphs[0].Runs.Add(r);
Creating shapes in the Word document is slightly more complicated. Because the Silverlight Open XML library doesn’t have built in classes for DrawingML, we have to extend it with our own.
The result is a new Drawing object that just like the Text object in the code above is placed inside a Run. The Drawing object has properties for its color, shape, position and size which it then uses to write out the necessary Open XML.
Note that they Drawing object writes a lot of XML and is too large to include here. Download the source code to see its detail.
To create the Drawing objects we read over the shapes on the drawing canvas. By reading the properties of the Silverlight shapes: color, position and size, we’re able to accurately recreate them in the Word document.
private void AddDocumentShapes(DocumentPart doc)
Paragraph p = doc.CreateElement<Paragraph>();
int id = 1;
foreach (Shape shape in DrawingCanvas.Children.OfType<Shape>())
ShapeType shapeType = (shape is Rectangle) ? ShapeType.Rectangle : ShapeType.Oval;
if (!double.IsNaN(shape.Width) && !double.IsNaN(shape.Height))
Drawing drawing = doc.CreateElement<Drawing>();
drawing.Left = Convert.ToInt32(Canvas.GetLeft(shape));
drawing.Top = Convert.ToInt32(Canvas.GetTop(shape));
drawing.Width = Convert.ToInt32(Convert.ToInt32(shape.Width));
drawing.Height = Convert.ToInt32(Convert.ToInt32(shape.Height));
drawing.ShapeType = shapeType;
drawing.FillColor = ((SolidColorBrush) shape.Fill).Color;
drawing.Id = id;
r.Content.Add(drawing);
id++;
p.Runs.Add(r);
doc.Sections[0].Paragraphs.Add(p);
And that is all there is to it. Once the title and shapes have been added to the WordDocument its content is written to the saved file and it is ready to open.
This application saves the file locally which is perfect for a simple demo but there is no reason why it couldn’t extend to more real world usage. From Silverlight the document can be saved via web services to your own custom ASP.NET website, a SharePoint document library or an Azure blob storage account.