Sharing the goodness…
Beth Massi is a Senior Program Manager on the Visual Studio team at Microsoft and a community champion for .NET developers. Learn more about Beth.
More videos »
A while back a posted how to use Word to create simple reports for LightSwitch by passing in an entity (like Customer) and using Word Content Controls to lay out content in a template and bind them to XML inside the document. If you missed it: Using Microsoft Word to Create Reports For LightSwitch (or Silverlight)
In the comment thread to that post there were requests on how to create master detail reports, for instance an Order and OrderDetails. In my last post I released a sample that shows one way to achieve this. The code is part of a larger LightSwitch sample application: Contoso Construction - LightSwitch Advanced Development Sample. In that sample I use the same technique in the post referenced above to add a helper class and Word document template to the client project and bind XML to content controls. The only difference to achieve the master-detail formatting is in the layout of the content controls and the code that generates the XML.
In the Contoso Construction sample, we have a parent “Project” table that has many “ProjectMaterials”. If you open the project screen you will see a button at the top that allows you to generate a project status report which displays fields from the Customer, Project and all the ProjectMaterials used on the construction project.
Project has a one-to-many relationship to ProjectMaterials so we could have one or many lines of materials to display. One way to do this is to lay out a single content control that will contain multiple lines like so:
So in this case I have four content controls representing the four fields I want to display off of the ProjectMaterial entity. Then all you need to do when generating the XML is to iterate the collection of children and put line breaks between them. You can do this easily using the Join method which takes an array and creates a string representation of the contents with a delimiter you specify, in my case I’m using the carriage return (vbCr). So in the MyReportHelper class we have code like so, paying particular attention to how I’m generating the <projectmaterials> node:
Public Shared Sub RunProjectStatusReport(ByVal project As Project)
If AutomationFactory.IsAvailable Then
'Create the XML data from our entity properties.
' Project materials content controls on the Word template are set to allow carriage
' returns so we can easily display as many line items as we need '
Dim myXML = <customer>
<fullname><%= project.Customer.FullName %></fullname>
<homephone><%= project.Customer.HomePhone %></homephone>
<mobilephone><%= project.Customer.MobilePhone %></mobilephone>
<email><%= project.Customer.Email %></email>
<fulladdress><%= project.Customer.FullAddress %></fulladdress>
<projectname><%= project.ProjectName %></projectname>
<startdate><%= project.StartDate.ToShortDateString %></startdate>
<estimatedenddate><%= project.EstmatedEndDate.ToShortDateString %></estimatedenddate>
<originalestimate><%= Format(project.OriginalEstimate, "c2") %></originalestimate>
<labor><%= Format(project.Labor, "c2") %></labor>
<totalcost><%= Format(project.TotalCost, "c2") %></totalcost>
<notes><%= project.Notes %></notes>
<summary><%= Join((From m In project.ProjectMaterials
Select m.Summary).ToArray, vbCr) %></summary>
<quantity><%= Join((From m In project.ProjectMaterials
Select CStr(m.Quantity)).ToArray, vbCr) %></quantity>
<price><%= Join((From m In project.ProjectMaterials
Select Format(m.Price, "c2")).ToArray, vbCr) %></price>
<itemtotal><%= Join((From m In project.ProjectMaterials
Select Format(m.ItemTotal, "c2")).ToArray, vbCr) %></itemtotal>
Using word = AutomationFactory.CreateObject("Word.Application")
'The report template already has content controls bound to XML inside.
' Look in the ClientGenerated project to view the Word template.
Dim resourceInfo = System.Windows.Application.GetResourceStream( New Uri("ProjectStatus.docx", UriKind.Relative))
Dim fileName = CopyStreamToTempFile(resourceInfo.Stream, ".docx")
Dim doc = word.Documents.Open(fileName)
'Grab the existing bound custom XML in the doc
Dim customXMLPart = doc.CustomXMLParts("urn:microsoft:contoso:projectstatus")
Dim all = customXMLPart.SelectSingleNode("//*")
Dim replaceNode = customXMLPart.SelectSingleNode("/ns0:root/customer")
'replace the <customer> node in the existing custom XML with this new data
word.Visible = True
Catch ex As Exception
Throw New InvalidOperationException("Failed to create project status report.", ex)
Hope this helps. For details on how to create the Word templates, bind them to XML and how to create the MyReportHelper class please read Using Microsoft Word to Create Reports For LightSwitch (or Silverlight).
Another great post, Beth. Congratulations!
But I think that LightSwitch MUST HAVE a built-in tool or something else to make reports and data consolidations EASIER.
DevExpress announced that they are providing XtraReports integration with LightSwich as an extension. Check out:community.devexpress.com/.../lightswitch-reporting-preview.aspx
Thank you for the great article and the sample. I have a question. I have similar table as the sample and added 'note' in each material. I realized, the row are not properly align when the 'note' content is too long. Do you have any suggestion on how i can overcome it?
I'm starting in LightSwitch. I using this tutorial as guidance, but I'm using C#. Is there any reference for the code in C# ?
Thank you very much