Search code examples
c#ms-wordoffice-automation

MS Word interop: How much text can fit into a cell


Is it possible to tell how much of a given text can fit into a table cell? This example puts everything in the first cell, I need to split it in two without resizing the first cell or changing the font.

using System.IO;
using System.Reflection;
using Word = Microsoft.Office.Interop.Word;

class Program
{
    static void Main()
    {
        string filename = "example.docx";
        string text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor";

        var wordApp = new Word.Application { Visible = false };
        string path = Path.Combine(Directory.GetCurrentDirectory(), filename);
        var doc = wordApp.Documents.Open(path, ReadOnly: false, Visible: true);
        doc.Activate();
        var table = doc.Tables[1];


        // todo: truncate text by the cell's size
        table.Cell(1, 1).Range.Text = text;

        string text2 = "";
        // todo: put the remainder of the truncated text to text2
        table.Cell(2, 1).Range.Text = text2;


        doc.Save();
        object missing = Missing.Value;
        doc.Close(ref missing, ref missing, ref missing);
        wordApp.Quit(ref missing, ref missing, ref missing);
    }
}

Solution

  • @macropod led me to the idea of one dirty hack (not that there is any clean way to work with Word anyway): just keep pushing text into the cell until its height changes. This is enough for my purpose, but one can check width as well.

    I use next row's Y position to determine previous one's height. So, as a limitation, there should be at least one more row below. Also, page number should be checked too.

    using System.Diagnostics;
    using System.IO;
    using System.Reflection;
    using Word = Microsoft.Office.Interop.Word;
    
    class Program
    {
        static void Main()
        {
            string filename = "example.docx";
            string text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor";
            int row = 1;
            int column = 1;
    
    
            var wordApp = new Word.Application { Visible = true };
            string path = Path.Combine(Directory.GetCurrentDirectory(), filename);
            var doc = wordApp.Documents.Open(path, ReadOnly: false, Visible: true);
            doc.Activate();
            var table = doc.Tables[1];
    
    
            // Add as much text to the cell (row,column) as possible without changing the height of the cell.
    
            // Row's bottom Y coordinate can be determined by the position of the next row and its page number.
            Debug.Assert(table.Rows.Count > row, "Need at least 1 more row below");
            table.Rows[row + 1].Select();
            float oldBottom = wordApp.Selection.Information[Word.WdInformation.wdVerticalPositionRelativeToPage];
            int oldPage = wordApp.Selection.Information[Word.WdInformation.wdActiveEndPageNumber];
    
            // Binary-searching the length of the longest fitting substring
            int min = 0;
            int max = text.Length;
            int length = 0;
            while (min < max)
            {
                length = (min + max) / 2;
                table.Cell(row, column).Range.Text = text.Substring(0, length);
                float bottom = wordApp.Selection.Information[Word.WdInformation.wdVerticalPositionRelativeToPage];
                float page = wordApp.Selection.Information[Word.WdInformation.wdActiveEndPageNumber];
                if (page > oldPage || bottom > oldBottom)
                    max = length - 1;
                else
                    min = length + 1;
            }
    
    
            // Don't split words
            while (length > 0 && char.IsLetterOrDigit(text[length - 1]))
                length--;
            table.Cell(row, column).Range.Text = text.Substring(0, length);
    
    
            doc.Save();
            object missing = Missing.Value;
            doc.Close(ref missing, ref missing, ref missing);
            wordApp.Quit(ref missing, ref missing, ref missing);
        }
    }