[Solved] Adding Word content from a blob to a Word Report Layout

PConijn
Member Posts: 31
Hi all,
I have a question not entirely dissimilar to this one.
Background Information
We have the option to store equipment configuration option specs in a Word document and attach it as a blob to that configuration option record. These specs contained text, tables and/or pictures, all in one.
In the "old days" (pre-Word Layout) I tinkered a way to load these specs as Word building blocks (autotext); the user could then add these in the Word report after generation.
Intended Change in Functionality
In the new structure with Word report layouts etc., we would like to use the Word layout to add these blobs to the Word layout, so that when an option is added to the configuration, the specs are automagically loaded and inserted at the placeholder.
For this, I would need to do two things:
1) Extract the content of the stored specs Word document or store only the content of the specs Word document - this is doable;
2) Somehow insert the content at the location of the placeholder.
Question
The question centers around aforementioned action no. 2: how do I insert that content (containing various elements) in that location at runtime?
In designing the Word layout, you need to insert the blob field as a text, RichText, picture, etc.
I can get the blob content in there as text, and even the Word content, but it's still xml and, naturally, text won't abide pictures and tables, so I will need to insert it at the xml level.
The merge process seems to take place in a closed NAV library (Microsoft.Dynamics.Nav.DocumentReport.WordReportManager), which means it's inaccessible code.
Any tips, hints or epiphanies?
I have a question not entirely dissimilar to this one.
Background Information
We have the option to store equipment configuration option specs in a Word document and attach it as a blob to that configuration option record. These specs contained text, tables and/or pictures, all in one.
In the "old days" (pre-Word Layout) I tinkered a way to load these specs as Word building blocks (autotext); the user could then add these in the Word report after generation.
Intended Change in Functionality
In the new structure with Word report layouts etc., we would like to use the Word layout to add these blobs to the Word layout, so that when an option is added to the configuration, the specs are automagically loaded and inserted at the placeholder.
For this, I would need to do two things:
1) Extract the content of the stored specs Word document or store only the content of the specs Word document - this is doable;
2) Somehow insert the content at the location of the placeholder.
Question
The question centers around aforementioned action no. 2: how do I insert that content (containing various elements) in that location at runtime?
In designing the Word layout, you need to insert the blob field as a text, RichText, picture, etc.
I can get the blob content in there as text, and even the Word content, but it's still xml and, naturally, text won't abide pictures and tables, so I will need to insert it at the xml level.
The merge process seems to take place in a closed NAV library (Microsoft.Dynamics.Nav.DocumentReport.WordReportManager), which means it's inaccessible code.
Any tips, hints or epiphanies?
0
Best Answer
-
I solved it.
Using the Microsoft.Office.Interop.Word libraries, I was able to loop through the content controls of the Word Report Layout at time of printing and look for a specific XPath in the CustomLayout xml (stored in the Custom Report Layout table).
Using that XPath, I was then able to replace the content control with the content of the WordDocument.Content range of the previously stored Word blob.
At this point it does require the report to use the actual table with the stored blob, given that the XPath search string is hard-coded, but that does not present practical issues at this point.
Getting the XPath
In order to get the correct XPath, please refer to this C# code snippet. It is usable as dll, but also not hard to code into NAV itself.
We can now add pre-stored Word blobs to our Word report layout in runtime.
We will need to test more, but this is the business part of the code.LOCAL FillBuildingBlockInWord(pTxtXPath : Text;pTxtBuildingBlockPath : Text) //Loop through the content controls in the printed Word Report layout FOREACH netWordContentControl IN netWordContentControls DO BEGIN //If the XPaths match, find the Word Block and replace the content control with it IF netWordContentControl.XMLMapping.XPath = pTxtXPath THEN BEGIN lNetContentControlRange := netWordContentControl.Range; //The range of the report Word Layout content control //Open the building block Word document we saved earlier lNetBBWordApp := lNetBBWordAppClass.ApplicationClass; lNetBBWordApp.Visible := FALSE; lNetBBWordDoc := netWordHelper.CallOpen(lNetBBWordApp, pTxtBuildingBlockPath, FALSE, FALSE); lNetBBContentRange := lNetBBWordDoc.Content; //Get the contents of the building block document //Try to add the building block content to the word document; if successful, delete the content contol (while leaving the data) IF TryAddContent(lNetContentControlRange, lNetBBContentRange) THEN netWordContentControl.Delete(FALSE); //Close the building block document netWordHelper.CallClose(lNetBBWordDoc, FALSE); CLEAR(lNetBBWordApp); END; END; //ForEach
TryAddContent function:LOCAL [TryFunction] TryAddContent(VAR pRefNetWordRange : DotNet "Microsoft.Office.Interop.Word.Range" RUNONCLIENT;VAR pRefNetBuildingBlockRange : DotNet "Microsoft.Office.Interop.Word.Range" RUNONCLIENT) pRefNetWordRange.InsertXML(pRefNetBuildingBlockRange.XML(FALSE), lNetObject);
0
Answers
-
I solved it.
Using the Microsoft.Office.Interop.Word libraries, I was able to loop through the content controls of the Word Report Layout at time of printing and look for a specific XPath in the CustomLayout xml (stored in the Custom Report Layout table).
Using that XPath, I was then able to replace the content control with the content of the WordDocument.Content range of the previously stored Word blob.
At this point it does require the report to use the actual table with the stored blob, given that the XPath search string is hard-coded, but that does not present practical issues at this point.
Getting the XPath
In order to get the correct XPath, please refer to this C# code snippet. It is usable as dll, but also not hard to code into NAV itself.
We can now add pre-stored Word blobs to our Word report layout in runtime.
We will need to test more, but this is the business part of the code.LOCAL FillBuildingBlockInWord(pTxtXPath : Text;pTxtBuildingBlockPath : Text) //Loop through the content controls in the printed Word Report layout FOREACH netWordContentControl IN netWordContentControls DO BEGIN //If the XPaths match, find the Word Block and replace the content control with it IF netWordContentControl.XMLMapping.XPath = pTxtXPath THEN BEGIN lNetContentControlRange := netWordContentControl.Range; //The range of the report Word Layout content control //Open the building block Word document we saved earlier lNetBBWordApp := lNetBBWordAppClass.ApplicationClass; lNetBBWordApp.Visible := FALSE; lNetBBWordDoc := netWordHelper.CallOpen(lNetBBWordApp, pTxtBuildingBlockPath, FALSE, FALSE); lNetBBContentRange := lNetBBWordDoc.Content; //Get the contents of the building block document //Try to add the building block content to the word document; if successful, delete the content contol (while leaving the data) IF TryAddContent(lNetContentControlRange, lNetBBContentRange) THEN netWordContentControl.Delete(FALSE); //Close the building block document netWordHelper.CallClose(lNetBBWordDoc, FALSE); CLEAR(lNetBBWordApp); END; END; //ForEach
TryAddContent function:LOCAL [TryFunction] TryAddContent(VAR pRefNetWordRange : DotNet "Microsoft.Office.Interop.Word.Range" RUNONCLIENT;VAR pRefNetBuildingBlockRange : DotNet "Microsoft.Office.Interop.Word.Range" RUNONCLIENT) pRefNetWordRange.InsertXML(pRefNetBuildingBlockRange.XML(FALSE), lNetObject);
0 -
Hi Peter,
I want to know from where to run your code and variables of what types in your function?
I need is to add additional pages to a word document created from a report using the saveaspdf function with the content from another word documents stored in NAV as attachment to the Sales Quote. As I understand, it is possible with your method?
Regard,
Vyacheslav0 -
Hi Vyacheslav,
Thank you for reaching out. Yes, it's certainly possible using this, but you don't need to loop through content controls like I do, nor do you need the whole bit about XPath.
I would remind you, however, that this solution was based on C/AL and uses .NET interop, which, going forward, will be tougher in AL.
The functionality can be called in codeunit 9651, in the MergeWordLayout function, just after the line:OutStrWordDoc := NAVWordXMLMerger.MergeWordDocument(InStrWordDoc,InStrXmlData,OutStrWordDoc) ;
Almost all of the .NET variables all come from the Microsoft.Office.Interop.Word assembly.lNetBBWordApp = Microsoft.Office.Interop.Word.Application lNetBBWordDoc = Microsoft.Office.Interop.Word.Document lNetBBContentRange = Microsoft.Office.Interop.Word.Range lNetContentControlRange = Microsoft.Office.Interop.Word.Range netWordContentControl = Microsoft.Office.Interop.Word.ContentControl
WordHelper is a Dynamics NAV assembly:netWordHelper = Microsoft.Dynamics.Nav.Integration.Office.Word.WordHelper
It always helps me to search for similar code in C# and translate that back to C/AL. StackOverflow specifically often gives you a lot of information.0
Categories
- All Categories
- 73 General
- 73 Announcements
- 66.6K Microsoft Dynamics NAV
- 18.7K NAV Three Tier
- 38.4K NAV/Navision Classic Client
- 3.6K Navision Attain
- 2.4K Navision Financials
- 116 Navision DOS
- 851 Navision e-Commerce
- 1K NAV Tips & Tricks
- 772 NAV Dutch speaking only
- 617 NAV Courses, Exams & Certification
- 2K Microsoft Dynamics-Other
- 1.5K Dynamics AX
- 320 Dynamics CRM
- 111 Dynamics GP
- 10 Dynamics SL
- 1.5K Other
- 990 SQL General
- 383 SQL Performance
- 34 SQL Tips & Tricks
- 35 Design Patterns (General & Best Practices)
- 1 Architectural Patterns
- 10 Design Patterns
- 5 Implementation Patterns
- 53 3rd Party Products, Services & Events
- 1.6K General
- 1.1K General Chat
- 1.6K Website
- 83 Testing
- 1.2K Download section
- 23 How Tos section
- 252 Feedback
- 12 NAV TechDays 2013 Sessions
- 13 NAV TechDays 2012 Sessions