none
Insert a button in a sentence RRS feed

  • Question

  • I have something similar to this with a WPF rich text box, but I was wondering how to insert a button inside a word document so it is obvious you can click that word and replace it.
    
    <p>In my add in I am doing this:</p>
    
    object missing = System.Reflection.Missing.Value;
    
    var newText = ActiveDocument.Range(ref missing, ref missing);
    
    var prevIndex = 0;
    for (int i = 0; i < sentence.Length; i++)
    {
    //I know there should be a single digit number between a pair of { } like {1}
    if (sentence[i] == '{' && sentence.Length > i + 2 && sentence[i + 2] == '}')
            {
              //get the number
              int dataIndex = -1;
              if (int.TryParse(sentence[i + 1].ToString(), out dataIndex))
              {
                //if (value.Tags.Count > dataIndex)
                {
                  //add all of the prev text up to the {
                  if (i - prevIndex > 0)
                    newText.InsertAfter(sentence.Substring(prevIndex, i - prevIndex));
                  object cast = (object)newText;
                  //add the tag
                  //AddMetaTag(value.Tags[dataIndex], sentenceTextBox.Blocks.Last<Block>().ElementEnd);
                  var name = "button" + dataIndex.ToString();
    
                  newText.SetRange(newText.End, newText.End);
                  var button = VSTODocument.Controls.AddButton(newText, 50, 16, "button" + Buttons.Count);
                  button.BackColor = new Color();
                  button.Tag = sentence;
                  button.Text = dataIndex.ToString();
                  Buttons.Add(button);
                  
                  //move up the index to after the end }
                  i += 2;
                  prevIndex = i + 1;
                }
              }
            }
          }
          newText.InsertAfter(sentence.Substring(prevIndex));
    

    The VSTODocument is just

    Globals

    .ThisAddIn.Application.ActiveDocument.GetVstoObject();

    The sentence is just something like: The brown {0} jumped over the {1}.

    Where the {#} I will be replacing them with buttons.

    Thanks, Wang

    Thursday, July 21, 2011 12:44 PM

Answers

  • Hi Wang

    It was a bit difficult to test your code as you didn't define everything in the sample you posted. I had to make some changes at my end in order to work it out, so you'll need to compare things in what I post here to what you actually have. The key element is in how to use the RANGE object.

        internal void insertButtonOnDoc()
        {
          Document vstoDoc = Globals.ThisAddIn.Application.ActiveDocument.GetVstoObject();
          Word.Range rng = Globals.ThisAddIn.Application.Selection.Range;
          string sentence = "The brown {0} jumped over the {1}";
          object oCollapseEnd = Word.WdCollapseDirection.wdCollapseEnd;
          object oChar = Word.WdUnits.wdCharacter;
          object o1 = 1;
          rng.Collapse(ref oCollapseEnd);
          int prevIndex = 0;
          for (int i = 0; i < sentence.Length; i++)
          {
            //I know there should be a single digit number between a pair of { } like {1}
            if (sentence[i] == '{' && sentence.Length > i + 2 && sentence[i + 2] == '}')
            {
              //get the number
              int dataIndex = -1;
              if (int.TryParse(sentence[i + 1].ToString(), out dataIndex))
              {
                //if (value.Tags.Count > dataIndex)
                {
                  //add all of the prev text up to the {
                  if (i - prevIndex > 0)
                    rng.Text = sentence.Substring(prevIndex, i - prevIndex);
                  //object cast = (object)rng;
                  //add the tag
                  //AddMetaTag(value.Tags[dataIndex], sentenceTextBox.Blocks.Last<Block>().ElementEnd);
                  string name = "button" + dataIndex.ToString();
    
                  rng.Collapse(ref oCollapseEnd);
                  var button = vstoDoc.Controls.AddButton(rng, 50, 16, "button"+ i.ToString());
                  button.Click += new EventHandler(button_Click);
                  button.BackColor = new System.Drawing.Color();
                  button.Tag = sentence;
                  button.Text = dataIndex.ToString();
                  //Buttons.Add(button);
    
                  //move up the index to after the end }
                  rng.MoveStart(ref oChar, ref o1);
                  i += 2;
                  prevIndex = i + 1;
                }
              }
            }
          }
          rng.Text =sentence.Substring(prevIndex);
        }
    

     


    Cindy Meister, VSTO/Word MVP
    • Marked as answer by cwang733t Monday, July 25, 2011 2:39 PM
    Friday, July 22, 2011 8:41 AM
    Moderator

All replies

  • Hi Wang

    It was a bit difficult to test your code as you didn't define everything in the sample you posted. I had to make some changes at my end in order to work it out, so you'll need to compare things in what I post here to what you actually have. The key element is in how to use the RANGE object.

        internal void insertButtonOnDoc()
        {
          Document vstoDoc = Globals.ThisAddIn.Application.ActiveDocument.GetVstoObject();
          Word.Range rng = Globals.ThisAddIn.Application.Selection.Range;
          string sentence = "The brown {0} jumped over the {1}";
          object oCollapseEnd = Word.WdCollapseDirection.wdCollapseEnd;
          object oChar = Word.WdUnits.wdCharacter;
          object o1 = 1;
          rng.Collapse(ref oCollapseEnd);
          int prevIndex = 0;
          for (int i = 0; i < sentence.Length; i++)
          {
            //I know there should be a single digit number between a pair of { } like {1}
            if (sentence[i] == '{' && sentence.Length > i + 2 && sentence[i + 2] == '}')
            {
              //get the number
              int dataIndex = -1;
              if (int.TryParse(sentence[i + 1].ToString(), out dataIndex))
              {
                //if (value.Tags.Count > dataIndex)
                {
                  //add all of the prev text up to the {
                  if (i - prevIndex > 0)
                    rng.Text = sentence.Substring(prevIndex, i - prevIndex);
                  //object cast = (object)rng;
                  //add the tag
                  //AddMetaTag(value.Tags[dataIndex], sentenceTextBox.Blocks.Last<Block>().ElementEnd);
                  string name = "button" + dataIndex.ToString();
    
                  rng.Collapse(ref oCollapseEnd);
                  var button = vstoDoc.Controls.AddButton(rng, 50, 16, "button"+ i.ToString());
                  button.Click += new EventHandler(button_Click);
                  button.BackColor = new System.Drawing.Color();
                  button.Tag = sentence;
                  button.Text = dataIndex.ToString();
                  //Buttons.Add(button);
    
                  //move up the index to after the end }
                  rng.MoveStart(ref oChar, ref o1);
                  i += 2;
                  prevIndex = i + 1;
                }
              }
            }
          }
          rng.Text =sentence.Substring(prevIndex);
        }
    

     


    Cindy Meister, VSTO/Word MVP
    • Marked as answer by cwang733t Monday, July 25, 2011 2:39 PM
    Friday, July 22, 2011 8:41 AM
    Moderator
  • Thanks a lot for the help, sadly I am still have the same issue in my addin.  It is a word addin, so you could probably place it anywhere.  ActiveDocument is -

     

    Globals.ThisAddIn.Application.ActiveDocument;

    and then I do ActiveDocument.GetVstoObject(); to my VSTODocument.

     

    This is an example of invoking the method:

    string test = "The brown {0} jumped over the lazy {1}";

    AddSentence(test);

     

     

    And the method itself

     

    private static void AddSentence(string sentence)
    
      {
    
       var Buttons = new List<Button>();
    
       object missing = System.Reflection.Missing.Value;
    
       object oCollapseEnd = Microsoft.Office.Interop.Word.WdCollapseDirection.wdCollapseEnd;
    
       var newText = ActiveDocument.Range(ref missing, ref missing);
    
    
    
       var prevIndex = 0;
    
       for (int i = 0; i < sentence.Length; i++)
    
       {
    
        //I know there should be a single digit number between a pair of { } like {1}
    
        if (sentence[i] == '{' && sentence.Length > i + 2 && sentence[i + 2] == '}')
    
        {
    
         //get the number
    
         int dataIndex = -1;
    
         if (int.TryParse(sentence[i + 1].ToString(), out dataIndex))
    
         {
    
          //if (value.Tags.Count > dataIndex)
    
          {
    
           //add all of the prev text up to the {
    
           if (i - prevIndex > 0)
    
            newText.InsertAfter(sentence.Substring(prevIndex, i - prevIndex));
    
    
    
           //object cast = (object)newText;
    
           //need a unique name for the button
    
           var name = "button" + Buttons.Count;
    
    
    
           newText.Collapse(ref oCollapseEnd);
    
           var button = VSTODocument.Controls.AddButton(newText, 50, 16, name);
    
           button.Tag = sentence;
    
           button.Text = dataIndex.ToString();
    
           Buttons.Add(button);
    
    
    
           //move up the index to after the end }
    
           i += 2;
    
           prevIndex = i + 1;
    
          }
    
         }
    
        }
    
       }
    
       newText.InsertAfter(sentence.Substring(prevIndex));
    
      }
    
    


    And this is what I ended up getting instead of the buttons being in the middle of the sentence:

     https://picasaweb.google.com/118283300485250225267/July252011?authuser=0&feat=directlink

     Thanks a lot!

     


    • Edited by cwang733t Monday, July 25, 2011 2:18 PM Define some components
    Monday, July 25, 2011 2:15 PM
  • If you don't incorporate ALL the changes I made to your method you won't get a proper result. Re-analyze the entire code sample I provided, you'll see I made more than one change. And I do NOT use Range.InsertAfter in the code I gave you.


    Cindy Meister, VSTO/Word MVP
    Monday, July 25, 2011 2:32 PM
    Moderator
  • Worked perfectly.  I guess I missed some of the changes through all of the monday monring.
    Monday, July 25, 2011 2:39 PM
  • Yeah, Monday mornings are always a lot of "fun". Glad you've got it working, now :-)
    Cindy Meister, VSTO/Word MVP
    Monday, July 25, 2011 3:14 PM
    Moderator
  • string[] test = {"Hello {0}.", "How are {1} today.", "This {3} is a test."}
    foreach(var testItem in test)
    {
     insertButtonOnDoc(testItem);
     var rng = Globals.ThisAddIn.Application.Selection.Range;
     rng.Collapse(ref oCollapseEnd);
     rng.Text = " ";
    }
    


    Ran into a second issue where if I did multiple sentences (ie loop through  string), it would always put the last period at the very end.

     

    Monday, July 25, 2011 6:54 PM
  • I figured it out.  If you share the same range between all of the methods, this fixed the issue.  FYI if anyone needing to do anything like this.
    Monday, July 25, 2011 8:02 PM