locked
Measuring the text cursor position RRS feed

  • Question

  • Hi.

    I am writing an application which renders documents from C# using word automation (I currently use Office 2003).

    My program is rendering information on a large size poster template (31.65cm width, 52.94cm height). So far, everything is going well, but something is bugging me.

    My poster contains 4 columns and as I fill each column with data, I would like to know where the text cursor position is located. Word has a nice status bar at the bottom which tells you the position of the cursor in centimetres. What I am aiming to do is decide if the cursor is getting close to 40cm down the page, then I want to output a single line message telling the reader that the information continues on the next column, then perform a clean column break and start on the next column.

    Is there any way I can return the coordinate properties of the cursor (like those in the status bar) back to my application so I can automate the column break at the right time?

    Thanks for any help!

    Kind Regards,

    Sean
    Wednesday, September 2, 2009 10:23 PM

Answers

  • Hi, I figured this out. It would appear that when you perform TypeText and TypeParagraph, the cursor position is not updated. In order to do this, I had to apply the following line to get the coordinate variables to refresh:

    wordApp.Selection.EndKey(ref unit, ref missing);
    vPosTextBoundary = sel.get_Information(Word.WdInformation.wdVerticalPositionRelativeToTextBoundary);
    vPosPage = sel.get_Information(Word.WdInformation.wdVerticalPositionRelativeToPage);

    This works only when the first line listed above is detected. I then convert the position from word points to cm like this:

    // Detect if cursor is greater or equal to 42cm down the page.
    if ((Convert.ToSingle(vPosPage) / 72.0f) * 2.54 >= 42.0f)
    {
    	object ColumnBreak = new object();
    	ColumnBreak = Word.WdBreakType.wdColumnBreak;
    	wordApp.Selection.InsertBreak(ref ColumnBreak);
    }

    Thanks for your tips. I'm glad I've got this worked out now.

    Kind regards,

    Sean
    • Marked as answer by Sean Connolly Tuesday, September 8, 2009 10:45 AM
    Tuesday, September 8, 2009 10:44 AM

All replies

  • Hi Sean!

    You can use the get_Information() method of the Word.Selection object:



    Word.Selection sel = Globals.ThisAddIn.Application.Selection;

    object vPosTextBoundary = sel.get_Information(Word.WdInformation.wdVerticalPositionRelativeToTextBoundary);
    object vPosPage = sel.get_Information(Word.WdInformation.wdVerticalPositionRelativeToPage);


    Note that the resulting value is in points where 72 points = 1 inch.

    Thursday, September 3, 2009 3:52 AM
  • Hi,

    Thanks for your reply. Unfortunately, the very first line won't compile under Visual C# 2005 Express Edition. Am I missing something which prevents this.

    I already had at the start of my function the following line
     using Word = Microsoft.Office.Interop.Word;

    I don't know if I need anything else.

    I tried changing the very first line of your reply to the following to see if that would work:
    Word.Selection sel = wordApp.Selection;

    This compiles as the wordApp declaration was made at the start of the function, but no matter how much text has already been written into the word document, the vPosTextBoundary always has a value of 375.15 and vPosPage always has a value of 530.55. I don't know if the line I replaced above is correct or not, but no errors are generated and it seems to execute without any exceptions being thrown.

    The word file was started from a document template with a pre-defined header and footer area. A rich text file is inserted from a file at the very beginning and all subsquent text is written in like this example.
    wordApp.Selection.TypeText("\t" + Utils.ToTitleCase(DestTrainData.Rows[j]["TerminationStation"].ToString()) + "\t"); wordApp.Selection.TypeText(DestTrainData.Rows[j]["TOCCode"].ToString()); wordApp.Selection.TypeParagraph();
     
    I thought I'd mention this in case this causes any problems.

    I have a meeting to discuss this in about 2.5 hours time. I doubt I will be able to implement this in time, but I still need to get this to work anyway.

    Thanks for your reply. It's a step in the right direction.
    Thursday, September 3, 2009 6:50 AM
  • Hi again!

    The first line of my code assumes that you have an addin project that implements the functionality you described.
    The line of code that you used to replace it is correct.

    Anyway, it works fine on my machine.
    This is my code. It is being executed everytime I press a button in the command bar:

    Word.Selection sel = Globals.ThisAddIn.Application.Selection;
    sel.TypeParagraph();
    object vPosTextBoundary = sel.get_Information(Word.WdInformation.wdVerticalPositionRelativeToTextBoundary);
    object vPosPage = sel.get_Information(Word.WdInformation.wdVerticalPositionRelativeToPage);


    May I see the block of code where you placed the get_Information() method?

    Thursday, September 3, 2009 9:20 AM
  • Hello , 

    I think Jose provided a pretty good idea, but he assuming you are woking on a VSTO add-in project, this is the reason why his code is not work for you.
    Alternatively, we could test above code in VBA, please press Alt+F11 in Word window and paste following code in VB editor, then press F5 run the macro:

    Sub Position()

    Debug.Print _
    Application.Selection.Information(wdHorizontalPositionRelativeToTextBoundary)
    Debug.Print _
    Application.Selection.Information(wdVerticalPositionRelativeToTextBoundary)

    End Sub

    If the result is different from Visual C# please make double check how you assign the wordApp variable, and make sure there's only one WinWord.exe is running in task manager.

    Thanks.

     

    Tim Li

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Thursday, September 3, 2009 10:07 AM
  • Hi, Sorry for the delay, but our client was here for an entire day and I strived to put a few last minute things into my project before her arrival.

    I have not used VSTO before, I am just using word automation instead, my application uses an added COM reference as follows:
    Microsoft Office 11.0 Object library
    Microsoft Word 11.0 Object library

    At the start of my main function, I add the following reference line:

    using Word = Microsoft.Office.Interop.Word;
    

    Then I declare the following within my static class:

    public static Word.Application wordApp;
    public static Word.Document wordDoc;
    

    Then I initialize the word document as such:

    wordApp = new Word.Application();
    wordDoc = new Word.Document();
    			
    object missing = System.Reflection.Missing.Value;
    object fileName = "D:\\MyTemplate.dot";
    object newTemplate = true;
    object docType = 0;
    object isVisible = true;
    
    wordApp = new Word.ApplicationClass();
    wordDoc = wordApp.Documents.Add(ref fileName, ref newTemplate, ref docType, ref isVisible);
    wordApp.Visible = false;
    wordApp.ScreenUpdating = false;
    wordDoc.Activate();

    One of the first things I do is to write the poster name into the top of the opened template with the following command (by the way r.Cells[1] is a DataGridViewRow.

    wordDoc.ActiveWindow.Selection.TypeText("From " + r.Cells[1].Value.ToString() + "\r");

    Then I import a rich text file document for the base of the document as:

    string FilePath = PropertiesData.Rows[0]["BoxNotesFilePath"].ToString();
    if (FilePath.Substring(FilePath.Length - 1, 1) != "\\")
    	FilePath = FilePath + "\\";
    FilePath = FilePath + Utils.RemoveSymbols(OttisUserCompany) + "_" + PropertiesData.Rows[0]["ProfileName"].ToString() + ".rtf";
    wordDoc.ActiveWindow.Selection.InsertFile(FilePath, ref missing, ref missing, ref missing, ref missing);
    

    PropertiesData is a DataTable, Utils.RemoveSymbols() is a class of utilities I have built up to do some string manipulation.

    I noticed something though, before i imported the rtf file, I called the following:

    Word.Selection sel = wordApp.Selection;
    object vPosTextBoundary = sel.get_Information(Word.WdInformation.wdVerticalPositionRelativeToTextBoundary);
    object vPosPage = sel.get_Information(Word.WdInformation.wdVerticalPositionRelativeToPage);

    The vPosTextBoundary came up as 0.0, the vPosPage came up as 155.35. After I inserted the rtf file, I again measured the two values and the vPosTextBoundary came up as 11.35 and vPosPage came up as 166.75.

    Later on, I execute the following:

    object unit = Microsoft.Office.Interop.Word.WdUnits.wdStory;
    wordApp.Selection.EndKey(ref unit, ref missing);
    wordApp.Selection.TypeParagraph();

    This takes me to the current end of the document, ready to write my main body of text. When I again measure the two positions, which are now vPosTextBoundary came up as 386.55 and vPosPage came up as 541.9.

    After this, I write complicated rows of text to the document which is too long winded to list here, but the are written something like this:

    wordApp.Selection.TypeText("Some Example Text");
    wordApp.Selection.TypeParagraph();
    

    After every paragraph row written, I checked the values again and they are no longer changing, so this has confused me.

    Any ideas???

    Kind regards,

    Sean
    • Marked as answer by Sean Connolly Tuesday, September 8, 2009 10:44 AM
    • Unmarked as answer by Sean Connolly Tuesday, September 8, 2009 10:45 AM
    Friday, September 4, 2009 9:55 AM
  • Hi, I figured this out. It would appear that when you perform TypeText and TypeParagraph, the cursor position is not updated. In order to do this, I had to apply the following line to get the coordinate variables to refresh:

    wordApp.Selection.EndKey(ref unit, ref missing);
    vPosTextBoundary = sel.get_Information(Word.WdInformation.wdVerticalPositionRelativeToTextBoundary);
    vPosPage = sel.get_Information(Word.WdInformation.wdVerticalPositionRelativeToPage);

    This works only when the first line listed above is detected. I then convert the position from word points to cm like this:

    // Detect if cursor is greater or equal to 42cm down the page.
    if ((Convert.ToSingle(vPosPage) / 72.0f) * 2.54 >= 42.0f)
    {
    	object ColumnBreak = new object();
    	ColumnBreak = Word.WdBreakType.wdColumnBreak;
    	wordApp.Selection.InsertBreak(ref ColumnBreak);
    }

    Thanks for your tips. I'm glad I've got this worked out now.

    Kind regards,

    Sean
    • Marked as answer by Sean Connolly Tuesday, September 8, 2009 10:45 AM
    Tuesday, September 8, 2009 10:44 AM