Create a Table with dynamic Columns

0
CptnCookie posted this 03 July 2016

Hi there,

I need help on how I can create a Table with a variable number of columns and their name based on a xml data source.

I have tried to bind a list vertically to the outer right table column, but docentric doesn't allow that.

So how can I build a template from which I can extend a table horizontally via the xml? And is a special xml format needed for that?

thanks.

2 Posts
2 Points
13 Comments
Order By: Standard | Newest | Votes
0
jles posted this 27 April 2018

Rico,

Yes, you are right. That extra space is created by Paragraph objects. You can check ParagraphFormat and you will see you can specify SpaceAfter and SpaceBefore. These two guys are part of MS Word's anatomy which is pretty much complex and it is good to know it. Docentric Toolkit DOM closely follows MS Word's concepts, so you can learn the anatomy form our DOM.

The reason why the inserted sub document's content into the target document is that target document's DefaultTableStyle get's applied to the inserted table. Obviously, the subdocument and the target document have different character, paragraph and table default styles.

The only way to make sure the sub document retain exact appearance is to specify inline format properties for characters (on Run elements), paragraphs, tables, table rows and table cells. Or, a better way would be to make sure that the sub document has the same set of styles as the target document. You could achieve this (creating the sub document) by loading the target document and remove all contents before creating a table in it.

Let me know if this helped.

Thanks, Jure

154 Posts
294 Points
0
RicoMM posted this 27 April 2018

I already figured out the cause of the problem, which is generated by the format of paragraph. Lol. The DOM has many things I need to take care of. :P

8 Posts
9 Points
0
RicoMM posted this 27 April 2018

Hi Jure,

Thank you for the solution. I found out that I could convert the document into pdf to solve the problem, because I mainly use it in PDF to show the report file.

The technique provided is really helpful when I show demo in the word too.

Here is a new problem I encounter when I generate insert a subdocument file into the word template. Here is the code how I insert a document into subdocument element.

if (e.Element is SubDocumentElement)
            {
                if (e.Element.Name == "TableDocument")
                {
                    var data = File.ReadAllBytes("MasterMainBreakersVoltageTestSection.docx");
                    e.Element.AsSubDocument().Value = data;
                }
            }

When I use document.Save("pdf"), referred to the DOM document object, the converted pdf version looks as expected: enter image description here

Howerer, the output pdf from word template looks like this: enter image description here

Notice that there is extra space in the each table row. After I have done some tryouts to figure out the problem. I know there is a TableRowHeight property that I could control the row height as I want, but the fact is that I need to have the content automatically wrapped as shown in the picture. If I specify a height in the row format, the long wrapped content is truncated.

I did check the reason for the extra space in the word version of generated document. There is magic extra space after line. enter image description here

Can you give some clues what was wrong? :)

8 Posts
9 Points
0
jles posted this 25 April 2018

Roco,

Rendering of tables in PDF is a bit inconsistent with the MS Word behavior. While our PDF renderer honors table column widths, MS Word honors only widths set on table cells directly. This means that you will need to also set:

TableCell.TableCellFormat.PreferredWidth = TableWidth.Fixed(Length.FromCentimeters(1));

Let me know if this fixes your problem.

Regrads, Jure

154 Posts
294 Points
0
RicoMM posted this 25 April 2018

Thank you, looking forward to your information. :)

8 Posts
9 Points
0
jles posted this 24 April 2018

Hi Rico,

Let me check this with our developer. I'll get back to you as soon as I will know anything.

Thanks,

Jure

154 Posts
294 Points
0
RicoMM posted this 24 April 2018

Oh I forgot to tell you that the display is correct in the pdf generation.

8 Posts
9 Points
0
RicoMM posted this 24 April 2018

Hi Jure,

I forgot to tell you about the latest result in the research. It's been a while since the last time I work on the document generation, because I was interrupted by other task in the project. The work around is very helpful, which solves the problem in the need for the dynamic tables.

Now, I create a word subdocument first with tables and then insert it into word reporting template. However, I found that the column width has some problem in the presentation of word.

Incorrect width for table columns

For example, I specified 4 columns in a table, and define them with width 5, 2, 2, 2 centimeters, or 10,5,5,5 centimeters. The result in the document is always the same as shown in the screenshot above. Did I miss something in my code?

    private void AppendLinedTable(Document doc, SubTestTable tableData)
    {
        var numOfColumns = tableData.TableColumns;

        if (!string.IsNullOrEmpty(tableData.TableHeadline))
        {
            var headline = new Paragraph(new Run(tableData.TableHeadline)
            {
                CharacterFormat = new CharacterFormat { Bold = true }
            });
            doc.Body.Elements.Add(headline);
        }

        var table = new Table
        {
            TableFormat =
            {
                CellSpacing = 0,
                Alignment = TableHorizontalAlignment.Left
            }
        };

        doc.Body.Elements.Add(table);

        for (var i = 0; i < numOfColumns; i++)
        {
            table.Columns.Add(new TableColumn(Length.FromCentimeters(tableData.TableWidths[i])));
        }

        // Insert Headers
        InsertLinedHeaders(table, tableData);
        InsertDataRows(table, tableData);

Last edited 24 April 2018

8 Posts
9 Points
1
jles posted this 26 March 2018

Hi Rico,

Docentric Toolkit consists of two major parts/frameworks:

  • Reporting (template based document generation)
  • Document Object Model APIs

It seems like you are primarily using reporting. Note that you cannot directly mix reporting and DOM APIs. What you can do is you can use DOM APIs to create a sub document on the fly programmatically using DOM APIs and use it as a sub document in your main generating document. Below is a snippet of how to create a new document and create a template from scratch:

public static void CreateTable()
    {

        // Create a new Document.
        Document document = Document.New();

        // Table
        Table table = new Table();
        document.Body.Elements.Add(table);      // Add to the section.
        table.TableFormat.Borders = new TableBorders();
        table.TableFormat.CellSpacing = 0;// Length.FromCentimeters(0.1);
        table.Columns.AddRange
            (
                new TableColumn(Length.FromCentimeters(5)),
                new TableColumn(Length.FromCentimeters(2)),
                new TableColumn(Length.FromCentimeters(3))
            );

        // Row 1
        {
            TableRow tr1 = new TableRow();
            table.Elements.Add(tr1);
            // Cell 1
            TableCell tc1 = new TableCell() { ColumnSpan = 2 };
            tr1.Elements.Add(tc1);
            tc1.Elements.AddRange
            (
                new Paragraph
                (
                    new Run("This is Table Cell 1,1!!!")
                )
            );

            // Cell 3
            TableCell tc3 = new TableCell() { RowSpan = 2 };
            tc3.TableCellFormat.Borders = new TableCellBorders() { Top = new Border(BorderStyle.Single, Colors.Yellow, Length.FromCentimeters(0.15)) };
            tr1.Elements.Add(tc3);
            tc3.Elements.AddRange
            (
                new Paragraph
                (
                    new Run("This is Table Cell 1,3 This is Table Cell 1,3 This is Table Cell 1,3 This is Table Cell 1,3 This is Table Cell 1,3 This is Table Cell 1,3 This is Tablej Cellj 1,3"),
                    new Run("\n\nThis is Table Cell 1,3 This is Table Cell 1,3 This is Table Cell 1,3 This is Table Cell 1,3 This is Table Cell 1,3 This is Table Cell 1,3 This is Tablej Cellj 1,3")
                )
            );
        }

        // Row 2
        {
            TableRow tr2 = new TableRow();
            table.Elements.Add(tr2);

            // Cell 1
            TableCell tc1 = new TableCell() { RowSpan = 2 };
            tc1.TableCellFormat.Borders = new TableCellBorders() { Top = new Border(BorderStyle.Single, Colors.LightBlue, Length.FromCentimeters(0.3)), Bottom = new Border(BorderStyle.Single, Colors.LightGreen, Length.FromCentimeters(0.5)) };
            tr2.Elements.Add(tc1);
            tc1.Elements.AddRange
            (
                new Paragraph
                (
                    new Run("This is Table Cell 2,1")
                )
            );

            // Cell 2
            TableCell tc2 = new TableCell();
            tr2.Elements.Add(tc2);
            tc2.TableCellFormat.Borders = new TableCellBorders() { Left = new Border(BorderStyle.Single, Colors.Green, Length.FromCentimeters(0.2)) };
            tc2.Elements.AddRange
            (
                new Paragraph
                (
                    new Run("This is Table Cell 2,2")
                )
            );
        }

        // Row 3
        {
            TableRow tr3 = new TableRow();
            table.Elements.Add(tr3);

            // Cell 2
            TableCell tc2 = new TableCell() { ColumnSpan = 2 };
            tr3.Elements.Add(tc2);
            tc2.Elements.AddRange
            (
                new Paragraph
                (
                    new Run("This is Table Cell 3,2 This is Table Cell 3,2 This is Table Cell 3,2 This is Table Cell 3,2 This is Table Cell 3,2 This is Table Cell 3,2 This is Table Cellj 3,2")
                )
            );
        }

        // Row 4
        {
            TableRow tr4 = new TableRow();
            table.Elements.Add(tr4);
            // Cell 4,1
            TableCell tc1 = new TableCell() { ColumnSpan = 3 };
            tc1.TableCellFormat.Borders = new TableCellBorders() { Bottom = new Border(BorderStyle.Single, Colors.Goldenrod, Length.FromCentimeters(0.2)) };
            tr4.Elements.Add(tc1);
            tc1.Elements.AddRange
            (
                new Paragraph
                (
                    new Run("This is Table Cell 4,1")
                )
            );
        }

        // Paragraph (there always needs to be at least an empty paragraph at the end of a document)
        Paragraph p2 = new Paragraph
                        (
                            new Run("Table") { CharacterFormat = new CharacterFormat() { FontSize = 18, Foreground = Colors.Green, Bold = true } }
                        );
        document.Body.Elements.Add(p2);

        // Save the document.
        document.Save(@"CreateTable.docx");
    }

Let me know if this helped.

Best regards,

Jure Leskovec

154 Posts
294 Points
0
RicoMM posted this 23 March 2018

I found this old post which tells some very useful technique here. I need dynamic tables badly for different kinds of tables. How do we insert a table into a sub-document, by setting the value? It requires a byte array for it, so I got a bit confused.

e.Element.AsSubDocument().Value = ??

var table = new Table();
table.Columns.Add(new TableColumn(Length.FromCentimeters(10)));
table.Columns.Add(new TableColumn(Length.FromCentimeters(15)));

Btw, I created a table in code, and I found that there is a TableColumn which takes a preferred with as a parameter. Does that work something like dynamic column?

8 Posts
9 Points
1
jles posted this 07 July 2016

Hi,

Yes, you are right. Some of the elements are composite elements and those elements always expose their children through the 'Elements' property. If you need to manipulate the element tree, then you always do this through this collection. The 'Rows' collection, as you have already figured out yourself, is a calculated collection of 'TableRow' elements.

You might be asking yourself why such a complication. The answer is that Word DOM allows you to have not just 'TableRow' elements as direct children of a 'Table' but also some other element types (e.g. a content control can wrap a 'TableRow' or there can be a 'FieldStart' as a direct child). We will most probably add some helper classes that will make document building easier in one of the future versions of Docentric Toolkit.

If you are not sure in the future how a DOM element tree should be, just load a simple Word document and inspect the element tree structure.

I hope this helps,

Jure Leskovec

Last edited 07 July 2016

154 Posts
294 Points
0
CptnCookie posted this 06 July 2016

Hi,

I followed your advice of creating a sub document programmatically with the table included, but I can't figure out how I can insert rows into the new table. The Rows-Property of a Docentric.Documents.ObjectModel.Tables.Table has no Add()-Method or similar and I can't find an example on how I can create a table using the Docentric DOM API.

Can you give me a hint on that please?

Thank you

// Edit:

Ok, I figuerd it out. A row element have to be added to the element collection of the table. The row element have to have an equal amount of cells as the table has columns. A cell contains a paragraph in which a run element is. In the run element we can add the text.

So the Row-Property is just a shortcut to get all the row elements of the table.

Thank you for your help :)

Last edited 07 July 2016

2 Posts
2 Points
0
jles posted this 04 July 2016

Hi,

Thank you for the inquiry.The current version of Docentric Toolkit doesn't support dynamic pruning or adding table columns. This can only be done programmatically using DOM APIs.

The only solution to achive this using Docentric Toolkit would be to create another document programmatically using DOM APIs and then insert it in your master template during document generation time via a SUB DOCUMENT tagging element.

Let me know if this could be a viable solution for you.

Regards, Jure Leskovec

154 Posts
294 Points

Our 226165 members have posted 342 times in 101 discussions