Table left position

Hello all.
We use Aspose.Words and have the following issue with tables. When we inset a table into document using DocumentBuilder we got it’s left position closer to the left side of a page than left page margin (see image attached).
We adjust a table width to fit page size and margins. And we see that width is ok. But position of the table is incorrect.
We use the following code to fit table width:

protected static void FitTableToPageWidth(Table table)
{
    double tableWidth = GetTableWidth(table);
    double containerWidth = GetAvailableWidth(table);

    foreach(Row row in table.Rows)
    {
        foreach(Cell cell in row.Cells)
        {
            double cellRatio = cell.CellFormat.Width / tableWidth;
            cell.CellFormat.Width = cellRatio * containerWidth;
        }
    }
}

protected static double GetTableWidth(Table table)
{
    double tableWidth = 0;
    foreach(Row row in table.Rows)
    {
        double rowWidth = 0;
        foreach(Cell cell in row.Cells)
        {
            rowWidth += cell.CellFormat.Width;
        }
        tableWidth = Math.Max(tableWidth, rowWidth);
    }
    return tableWidth;
}

Can you help us to set up left position of the table right after left margin of a page?

Hello
Thanks for your request. Could you please attach your input and output documents here for testing. I will check them on my side and provide you more information.
Best regards,

Hello
In the attached zip input TableAlignment.docx and the output TableAlignment.pdf. Tag {!Proposal Payment Schedule} in the document replaces with the table.

Hello
Thank you for additional information. Could you please also provide me the code which will allow me to reproduce the problem on my side?
Best regards,

Hi there,

Thanks for your inquiry.

The observed behavior is actually correct. Microsoft Word is aligning the paragraphs in the table to the paragraphs in the document body. Please see the screenshot below.

To move the edge of the table to be in line with the body text you can use the Table.LeftIndent property. Please see the code below.

table.LeftIndent = table.FirstRow.FirstCell.CellFormat.LeftPadding;

Also note in the latest versions you also simply you code by removing FitTableToPageWidth and using the AutoFit method instead.

table.AutoFit(AutoFitBehavior.AutoFitToWindow);

If we can help with anything else, please feel free to ask.

Thanks,

Hello
First of all thank you for your reply.
I understand that the behavior is correct. But I want to draw my table’s left position right after red line you’ve drown. Table.LeftIndent is the property which helps me (I tried to set it’s value manualy in debug mode). But I don’t know which value defines that gap between left table line and a text of the cell. Unfortunately table.FirstRow.FirstCell.CellFormat.LeftPadding does not help me as it is 0 in my case (I tried it).
In the file attached TableAlignment.docx is a template where we replace {!Proposal Estimate} text with the table.
TableAlignment1.pdf - is the result we have if we use custom FitTableToPageWidth function.
TableAlignment2.pdf -is the result we have if we use table.AutoFit(AutoFitBehavior.AutoFitToWindow). Note the last row has undesired width. It should be the the whole table width as it is in TableAlignment1.pdf. Also it does not set the desired left position of the table and autofits column sizes to their content (we wanted column’s width changed proportionally).

Also note how the image (black rectangle) is alligned. We adjust it’s size using the function below. But it’s left position is undesirable. Seems it is the same problem as in the first cell.

protected static void FitImageSize(Table table, int columnIndex)
{
    foreach(Row row in table.Rows)
    {
        Cell pictureCell = row.Cells[columnIndex];
        if (pictureCell == null)
        {
            continue;
        }

        Shape imgShape = pictureCell.GetChild(NodeType.Shape, 0, true) as Shape;
        if (imgShape == null || imgShape.Width <= pictureCell.CellFormat.Width)
        {
            continue;
        }

        double newWidth;
        double newHeight;
        double desiredWidth = pictureCell.CellFormat.Width - pictureCell.CellFormat.LeftPadding -
            pictureCell.CellFormat.RightPadding;

        ImagesUtility.GetScaledImageSize(imgShape.Width, imgShape.Height, desiredWidth, null, out newWidth, out newHeight);

        imgShape.Width = newWidth;
        imgShape.Height = newHeight;
    }
}

So you’ll help us very much if you tell us how we can obtain that gap between left cell line and a text.
Also I’ve attached code sample which could help you to show how we generate the table.

Hi Valery,
Thank you for additional information. It is quite difficult to run your code because it has a lot of dependencies. So I created my own dummy code to show the workaround:

[Test]
public void Test001()
{
    Document doc = new Document(@"Test001\TableAlignment.docx");
    doc.Range.Replace(new Regex(@"\{!Proposal Estimate\}"), new ReplaceEvaluatorFindAndInsertTable(), false);
    doc.Save(@"Test001\out.docx");
}
private class ReplaceEvaluatorFindAndInsertTable: IReplacingCallback
{
    ///
    /// This method is called by the Aspose.Words find and replace engine for each match.
    /// This method replaces the match string, even if it spans multiple runs.
    ///
    ReplaceAction IReplacingCallback.Replacing(ReplacingArgs e)
    {
        // This is a Run node that contains either the beginning or the complete match.
        Node currentNode = e.MatchNode;
        // The first (and may be the only) run can contain text before the match,
        // in this case it is necessary to split the run.
        if (e.MatchOffset> 0)
            currentNode = SplitRun((Run) currentNode, e.MatchOffset);
        // This array is used to store all nodes of the match for further removing.
        ArrayList runs = new ArrayList();
        // Find all runs that contain parts of the match string.
        int remainingLength = e.Match.Value.Length;
        while ((remainingLength> 0) &&
            (currentNode != null) &&
            (currentNode.GetText().Length <= remainingLength))
        {
            runs.Add(currentNode);
            remainingLength = remainingLength - currentNode.GetText().Length;
            // Select the next Run node.
            // Have to loop because there could be other nodes such as BookmarkStart etc.
            do {
                currentNode = currentNode.NextSibling;
            }
            while ((currentNode != null) && (currentNode.NodeType != NodeType.Run));
        }
        // Split the last run that contains the match if there is any text left.
        if ((currentNode != null) && (remainingLength> 0))
        {
            SplitRun((Run) currentNode, remainingLength);
            runs.Add(currentNode);
        }
        // Create Document Buidler aond insert text
        DocumentBuilder builder = new DocumentBuilder(e.MatchNode.Document as Document);
        builder.MoveTo((Node) runs[runs.Count - 1]);
        BuildDummyTable(builder);
        // Now remove all runs in the sequence.
        foreach(Run run in runs)
        run.Remove();
        // Signal to the replace engine to do nothing because we have already done all what we wanted.
        return ReplaceAction.Skip;
    }
    ///
    /// Splits text of the specified run into two runs.
    /// Inserts the new run just after the specified run.
    ///
    private static Run SplitRun(Run run, int position)
    {
        Run afterRun = (Run) run.Clone(true);
        afterRun.Text = run.Text.Substring(position);
        run.Text = run.Text.Substring(0, position);
        run.ParentNode.InsertAfter(afterRun, run);
        return afterRun;
    }
    private static void BuildDummyTable(DocumentBuilder builder)
    {
        Table table = builder.StartTable();
        for (int i = 0; i <5; i++)
        {
            for (int j = 0; j <5; j++)
            {
                builder.InsertCell();
                builder.Write("test");
            }
            builder.EndRow();
        }
        builder.EndTable();
        table.LeftIndent += table.LeftPadding;
    }
}

I highlighted the line of code that should help you.
Please let us know in case of any issues, we are always glad to help you.
Best regards,

Hi there,

In regards to your second issue, just in case you are still having troubles with this. The behavior you see by using the new autofit method is correct, the table itself is fit to the page but it’s the cells in the table that are not sizing correctly.

I think you can achieve what you are looking for by instead using Table.AutoFit(AutoFitBehavior.FixedColumnWidths) and then setting Table.PreferredWidth = PreferredWidth.FromPercent(100). Hopefully this produces a better output.

If you are having any further issues could you please a DOCX document which contains the table generated by code before any autofit is applied.

Thanks,

Thank you guys alot.
I’ve found my issue. The issue caused by DocumentBuilder.RowFormat.ClearFormatting() method. We invoed it every time before starting draw a table.
So I remember RowFormat.LeftPadding into a local variable before drawing a table. Draw a table, fit it and then perfotm table.LeftIndent += tableLeftPadding.

I tried to use table.LeftPadding but it doesn’t have a correct value until we draw atleast one row. But when we draw the first row we have table.LeftPadding = 0 (due to RowFormat.ClearFormatting()).
So the is fixed but with workaround as I understand.

Thank you again

Hi
Thank you for additional information. It is perfect that you managed to resolve the issue. Please feel free to ask in case of any issues, we are always glad to help you.
Best regards,